From 7fe693bb574857008e8fdec8a3f1521b96952bac Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Thu, 19 Oct 2023 22:39:16 -0400 Subject: [PATCH 01/23] feat(itkwasm-image-io-wasi): add bindgen output --- .../python/itkwasm-image-io-wasi/README.md | 26 ++++++ .../itkwasm_image_io_wasi/__init__.py | 48 +++++++++++ .../itkwasm_image_io_wasi/_version.py | 1 + .../bio_rad_read_image.py | 76 ++++++++++++++++++ .../bio_rad_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/bmp_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/bmp_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/fdf_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/fdf_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/gdcm_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/gdcm_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/ge4_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/ge4_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/ge5_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/ge5_write_image.py | 79 +++++++++++++++++++ .../ge_adw_read_image.py | 76 ++++++++++++++++++ .../ge_adw_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/gipl_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/gipl_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/jpeg_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/jpeg_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/lsm_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/lsm_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/meta_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/meta_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/mgh_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/mgh_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/mrc_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/mrc_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/nifti_read_image.py | 76 ++++++++++++++++++ .../nifti_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/nrrd_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/nrrd_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/png_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/png_write_image.py | 79 +++++++++++++++++++ .../scanco_read_image.py | 76 ++++++++++++++++++ .../scanco_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/tiff_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/tiff_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/vtk_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/vtk_write_image.py | 79 +++++++++++++++++++ .../itkwasm_image_io_wasi/wasm_read_image.py | 76 ++++++++++++++++++ .../itkwasm_image_io_wasi/wasm_write_image.py | 79 +++++++++++++++++++ .../wasm_zstd_read_image.py | 76 ++++++++++++++++++ .../wasm_zstd_write_image.py | 79 +++++++++++++++++++ .../itkwasm-image-io-wasi/pyproject.toml | 59 ++++++++++++++ 46 files changed, 3389 insertions(+) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/README.md create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/pyproject.toml diff --git a/packages/image-io/python/itkwasm-image-io-wasi/README.md b/packages/image-io/python/itkwasm-image-io-wasi/README.md new file mode 100644 index 000000000..568ae8101 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/README.md @@ -0,0 +1,26 @@ +# itkwasm-image-io-wasi + +[![PyPI version](https://badge.fury.io/py/itkwasm-image-io-wasi.svg)](https://badge.fury.io/py/itkwasm-image-io-wasi) + +Input and output for scientific and medical image file formats. WASI implementation. + +This package provides the WASI WebAssembly implementation. It is usually not called directly. Please use [`itkwasm-image-io`](https://pypi.org/project/itkwasm-image-io/) instead. + + +## Installation + +```sh +pip install itkwasm-image-io-wasi +``` + +## Development + +```sh +pip install pytest +pip install -e . +pytest + +# or +pip install hatch +hatch run test +``` diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py new file mode 100644 index 000000000..ce7930497 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py @@ -0,0 +1,48 @@ +# Generated file. To retain edits, remove this comment. + +"""itkwasm-image-io-wasi: Input and output for scientific and medical image file formats. WASI implementation.""" + +from .bio_rad_read_image import bio_rad_read_image +from .bio_rad_write_image import bio_rad_write_image +from .bmp_read_image import bmp_read_image +from .bmp_write_image import bmp_write_image +from .fdf_read_image import fdf_read_image +from .fdf_write_image import fdf_write_image +from .gdcm_read_image import gdcm_read_image +from .gdcm_write_image import gdcm_write_image +from .ge_adw_read_image import ge_adw_read_image +from .ge_adw_write_image import ge_adw_write_image +from .ge4_read_image import ge4_read_image +from .ge4_write_image import ge4_write_image +from .ge5_read_image import ge5_read_image +from .ge5_write_image import ge5_write_image +from .gipl_read_image import gipl_read_image +from .gipl_write_image import gipl_write_image +from .jpeg_read_image import jpeg_read_image +from .jpeg_write_image import jpeg_write_image +from .lsm_read_image import lsm_read_image +from .lsm_write_image import lsm_write_image +from .meta_read_image import meta_read_image +from .meta_write_image import meta_write_image +from .mgh_read_image import mgh_read_image +from .mgh_write_image import mgh_write_image +from .mrc_read_image import mrc_read_image +from .mrc_write_image import mrc_write_image +from .nifti_read_image import nifti_read_image +from .nifti_write_image import nifti_write_image +from .nrrd_read_image import nrrd_read_image +from .nrrd_write_image import nrrd_write_image +from .png_read_image import png_read_image +from .png_write_image import png_write_image +from .scanco_read_image import scanco_read_image +from .scanco_write_image import scanco_write_image +from .tiff_read_image import tiff_read_image +from .tiff_write_image import tiff_write_image +from .vtk_read_image import vtk_read_image +from .vtk_write_image import vtk_write_image +from .wasm_read_image import wasm_read_image +from .wasm_write_image import wasm_write_image +from .wasm_zstd_read_image import wasm_zstd_read_image +from .wasm_zstd_write_image import wasm_zstd_write_image + +from ._version import __version__ diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py new file mode 100644 index 000000000..493f7415d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py @@ -0,0 +1 @@ +__version__ = "0.3.0" diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_read_image.py new file mode 100644 index 000000000..82b8f945d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def bio_rad_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('bio-rad-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_write_image.py new file mode 100644 index 000000000..9e7a513e6 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bio_rad_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def bio_rad_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('bio-rad-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_read_image.py new file mode 100644 index 000000000..a1ffc057c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def bmp_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('bmp-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_write_image.py new file mode 100644 index 000000000..865a54932 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/bmp_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def bmp_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('bmp-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_read_image.py new file mode 100644 index 000000000..c9a7d612a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def fdf_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('fdf-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_write_image.py new file mode 100644 index 000000000..a0cdd34a8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/fdf_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def fdf_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('fdf-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_read_image.py new file mode 100644 index 000000000..3eb0319f6 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def gdcm_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('gdcm-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_write_image.py new file mode 100644 index 000000000..8e4d8655f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gdcm_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def gdcm_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('gdcm-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_read_image.py new file mode 100644 index 000000000..b5e30347a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def ge4_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('ge4-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_write_image.py new file mode 100644 index 000000000..282a7d4aa --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge4_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def ge4_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('ge4-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_read_image.py new file mode 100644 index 000000000..93737d6f1 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def ge5_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('ge5-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_write_image.py new file mode 100644 index 000000000..a2c6af936 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge5_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def ge5_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('ge5-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_read_image.py new file mode 100644 index 000000000..c32ed5927 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def ge_adw_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('ge-adw-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_write_image.py new file mode 100644 index 000000000..73e9cb647 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/ge_adw_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def ge_adw_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('ge-adw-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_read_image.py new file mode 100644 index 000000000..78e5f8309 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def gipl_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('gipl-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_write_image.py new file mode 100644 index 000000000..cd30ad85a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/gipl_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def gipl_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('gipl-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_read_image.py new file mode 100644 index 000000000..00fc99370 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def jpeg_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('jpeg-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_write_image.py new file mode 100644 index 000000000..91abde9de --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/jpeg_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def jpeg_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('jpeg-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_read_image.py new file mode 100644 index 000000000..40139cbbd --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def lsm_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('lsm-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_write_image.py new file mode 100644 index 000000000..6d514a054 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/lsm_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def lsm_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('lsm-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_read_image.py new file mode 100644 index 000000000..2c089fb1b --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def meta_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('meta-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_write_image.py new file mode 100644 index 000000000..7621603b2 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/meta_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def meta_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('meta-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_read_image.py new file mode 100644 index 000000000..f1e1b5bc4 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def mgh_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('mgh-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_write_image.py new file mode 100644 index 000000000..dd0bbd292 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mgh_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def mgh_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('mgh-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_read_image.py new file mode 100644 index 000000000..3eb8090b8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def mrc_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('mrc-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_write_image.py new file mode 100644 index 000000000..10545767c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/mrc_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def mrc_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('mrc-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_read_image.py new file mode 100644 index 000000000..50708de9b --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def nifti_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('nifti-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_write_image.py new file mode 100644 index 000000000..af6dd59e2 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nifti_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def nifti_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('nifti-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_read_image.py new file mode 100644 index 000000000..a9d8a5c9d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def nrrd_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('nrrd-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_write_image.py new file mode 100644 index 000000000..b17598283 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/nrrd_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def nrrd_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('nrrd-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_read_image.py new file mode 100644 index 000000000..28913575f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def png_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('png-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_write_image.py new file mode 100644 index 000000000..cc87aac37 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/png_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def png_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('png-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_read_image.py new file mode 100644 index 000000000..cf5f84e2f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def scanco_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('scanco-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_write_image.py new file mode 100644 index 000000000..13c156c00 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/scanco_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def scanco_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('scanco-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_read_image.py new file mode 100644 index 000000000..94726c377 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def tiff_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('tiff-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_write_image.py new file mode 100644 index 000000000..fdd74a208 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/tiff_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def tiff_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('tiff-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_read_image.py new file mode 100644 index 000000000..8e0d92827 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def vtk_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('vtk-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_write_image.py new file mode 100644 index 000000000..45073f61b --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/vtk_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def vtk_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('vtk-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_read_image.py new file mode 100644 index 000000000..b804994be --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def wasm_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('wasm-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_write_image.py new file mode 100644 index 000000000..cad1b9158 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def wasm_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('wasm-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_read_image.py new file mode 100644 index 000000000..0fd5a0bbf --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_read_image.py @@ -0,0 +1,76 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + BinaryFile, + Image, +) + +def wasm_zstd_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('wasm-zstd-read-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.Image), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + args: List[str] = ['--memory-io',] + # Inputs + if not Path(serialized_image).exists(): + raise FileNotFoundError("serialized_image does not exist") + args.append(str(PurePosixPath(serialized_image))) + # Outputs + could_read_name = '0' + args.append(could_read_name) + + image_name = '1' + args.append(image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = ( + outputs[0].data, + outputs[1].data, + ) + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_write_image.py new file mode 100644 index 000000000..5aa343682 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_zstd_write_image.py @@ -0,0 +1,79 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path, PurePosixPath +import os +from typing import Dict, Tuple, Optional, List, Any + +from importlib_resources import files as file_resources + +_pipeline = None + +from itkwasm import ( + InterfaceTypes, + PipelineOutput, + PipelineInput, + Pipeline, + Image, + BinaryFile, +) + +def wasm_zstd_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + global _pipeline + if _pipeline is None: + _pipeline = Pipeline(file_resources('itkwasm_image_io_wasi').joinpath(Path('wasm_modules') / Path('wasm-zstd-write-image.wasi.wasm'))) + + pipeline_outputs: List[PipelineOutput] = [ + PipelineOutput(InterfaceTypes.JsonCompatible), + PipelineOutput(InterfaceTypes.BinaryFile, BinaryFile(PurePosixPath(serialized_image))), + ] + + pipeline_inputs: List[PipelineInput] = [ + PipelineInput(InterfaceTypes.Image, image), + ] + + args: List[str] = ['--memory-io',] + # Inputs + args.append('0') + # Outputs + could_write_name = '0' + args.append(could_write_name) + + serialized_image_name = str(PurePosixPath(serialized_image)) + args.append(serialized_image_name) + + # Options + input_count = len(pipeline_inputs) + if information_only: + args.append('--information-only') + + if use_compression: + args.append('--use-compression') + + + outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs) + + result = outputs[0].data + return result + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/pyproject.toml b/packages/image-io/python/itkwasm-image-io-wasi/pyproject.toml new file mode 100644 index 000000000..3b532ab1d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/pyproject.toml @@ -0,0 +1,59 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "itkwasm-image-io-wasi" +readme = "README.md" +license = "Apache-2.0" +dynamic = ["version"] +description = "Input and output for scientific and medical image file formats." +classifiers = [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: C++", + "Environment :: WebAssembly", + "Environment :: WebAssembly :: Emscripten", + "Environment :: WebAssembly :: WASI", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +keywords = [ + "itkwasm", + "webassembly", + "wasi", +] + +requires-python = ">=3.8" +dependencies = [ + "itkwasm >= 1.0.b131", + "importlib_resources", + +] + +[tool.hatch.version] +path = "itkwasm_image_io_wasi/_version.py" + +[tool.hatch.envs.default] +dependencies = [ + "pytest", +] + +[project.urls] +Home = "https://github.com/InsightSoftwareConsortium/itk-wasm" +Source = "https://github.com/InsightSoftwareConsortium/itk-wasm" + +[tool.hatch.envs.default.scripts] +test = "pytest" + + +[tool.hatch.build] +exclude = [ + "/examples", +] From 4ff0d0aa3542de84eae1325e9faf4e11b02107c9 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Thu, 19 Oct 2023 23:03:33 -0400 Subject: [PATCH 02/23] test: add wasi bio-rad test --- .../itkwasm-image-io-wasi/tests/__init__.py | 0 .../itkwasm-image-io-wasi/tests/common.py | 6 +++ .../tests/test_bio_rad.py | 44 +++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/__init__.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/common.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/test_bio_rad.py diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/__init__.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/common.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/common.py new file mode 100644 index 000000000..caf5bf5d9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/common.py @@ -0,0 +1,6 @@ +from pathlib import Path + +test_input_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "input" +test_baseline_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "baseline" +test_output_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "python" +test_output_path.mkdir(parents=True, exist_ok=True) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_bio_rad.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_bio_rad.py new file mode 100644 index 000000000..5ecff2a64 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_bio_rad.py @@ -0,0 +1,44 @@ +from pathlib import Path + +from itkwasm_image_io_wasi import bio_rad_read_image, bio_rad_write_image + +from .common import test_input_path, test_output_path + +test_input_file_path = test_input_path / "biorad.pic" +test_output_file_path = test_output_path / "biorad.pic" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 0.06000000238418579 + assert image.spacing[1] == 0.06000000238418579 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 768 + assert image.size[1] == 512 + assert image.data.shape[1] == 768 + assert image.data.shape[0] == 512 + assert image.data.ravel()[1000] == 27 + +def test_bio_rad_read_image(): + could_read, image = bio_rad_read_image(test_input_file_path) + assert could_read + verify_image(image) + +def test_bio_rad_write_image(): + could_read, image = bio_rad_read_image(test_input_file_path) + assert could_read + + use_compression = False + could_write = bio_rad_write_image(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = bio_rad_read_image(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file From 020ac77129935874e433893145fddb66feca779f Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 20 Oct 2023 00:17:49 -0400 Subject: [PATCH 03/23] feat(itkwasm-image-io-wasi): add read_image, imread --- .../core/python/itkwasm/itkwasm/cast_image.py | 16 +++- .../itkwasm_image_io_wasi/__init__.py | 4 +- .../extension_to_image_io.py | 56 ++++++++++++++ .../itkwasm_image_io_wasi/image_io_index.py | 25 ++++++ .../itkwasm_image_io_wasi/read_image.py | 77 +++++++++++++++++++ .../itkwasm-image-io-wasi/tests/test_png.py | 43 +++++++++++ .../tests/test_read_write_image.py | 58 ++++++++++++++ .../typescript/src/extension-to-image-io.ts | 1 + 8 files changed, 277 insertions(+), 3 deletions(-) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/extension_to_image_io.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/test_png.py create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py diff --git a/packages/core/python/itkwasm/itkwasm/cast_image.py b/packages/core/python/itkwasm/itkwasm/cast_image.py index 81f77ae20..351561e95 100644 --- a/packages/core/python/itkwasm/itkwasm/cast_image.py +++ b/packages/core/python/itkwasm/itkwasm/cast_image.py @@ -12,7 +12,21 @@ def cast_image(input_image: Image, pixel_type: Optional[PixelTypes]=None, component_type: Optional[Union[IntTypes, FloatTypes]]=None) -> Image: - """Cast an image to another pixel type and / or component type.""" + """Cast an image to another pixel type and / or component type. + + :param input_image: Image to be cast. + :type input_image: Image + + :param pixel_type: Pixel type to cast to. + :type pixel_Type: Optional[PixelTypes] + + :param component_type: Component type to cast to. + :type component_type: Optional[Union[IntTypes, FloatTypes]] + + :return: Cast image. Event if pixel_type or component_type are not specified, a copy is made. + :rtype: Image + + """ output_image_type = ImageType(**asdict(input_image.imageType)) if pixel_type is not None: diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py index ce7930497..9f8a84c22 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py @@ -1,7 +1,7 @@ -# Generated file. To retain edits, remove this comment. - """itkwasm-image-io-wasi: Input and output for scientific and medical image file formats. WASI implementation.""" +from .read_image import read_image, imread + from .bio_rad_read_image import bio_rad_read_image from .bio_rad_write_image import bio_rad_write_image from .bmp_read_image import bmp_read_image diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/extension_to_image_io.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/extension_to_image_io.py new file mode 100644 index 000000000..b3c98f49c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/extension_to_image_io.py @@ -0,0 +1,56 @@ +from collections import OrderedDict + +extension_to_image_io = OrderedDict([ + ('.bmp', 'bmp'), + + ('.dcm', 'gdcm'), + + ('.gipl', 'gipl'), + ('.gipl.gz', 'gipl'), + + ('.hdf5', 'hdf5'), + + ('.jpg', 'jpeg'), + ('.jpeg', 'jpeg'), + + ('.iwi', 'wasm'), + ('.iwi.cbor', 'wasm'), + ('.iwi.cbor.zst', 'wasm_zstd'), + + ('.lsm', 'lsm'), + + ('.mnc', 'mnc'), + ('.mnc.gz', 'mnc'), + ('.mnc2', 'mnc'), + + ('.mgh', 'mgh'), + ('.mgz', 'mgh'), + ('.mgh.gz', 'mgh'), + + ('.mha', 'meta'), + ('.mhd', 'meta'), + + ('.mrc', 'mrc'), + + ('.nia', 'nifti'), + ('.nii', 'nifti'), + ('.nii.gz', 'nifti'), + ('.hdr', 'nifti'), + + ('.nrrd', 'nrrd'), + ('.nhdr', 'nrrd'), + + ('.png', 'png'), + + ('.pic', 'bio_rad'), + + ('.tif', 'tiff'), + ('.tiff', 'tiff'), + + ('.vtk', 'vtk'), + + ('.isq', 'scanco'), + ('.aim', 'scanco'), + + ('.fdf', 'fdf'), +]) diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py new file mode 100644 index 000000000..de339c7c0 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py @@ -0,0 +1,25 @@ +image_io_index = [ + 'png', + 'meta', + 'tiff', + 'nifti', + 'jpeg', + 'nrrd', + 'vtk', + 'bmp', + 'hdf5', + 'minc', + 'mrc', + 'lsm', + 'mgh', + 'bio_rad', + 'gipl', + 'ge_adw', + 'ge4', + 'ge5', + 'gdcm', + 'scanco', + 'wasm', + 'wasm_zstd', +] + diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py new file mode 100644 index 000000000..17e7f4ccc --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py @@ -0,0 +1,77 @@ +import os +import importlib +from pathlib import Path +from typing import Optional, Union + +from itkwasm import Image, PixelTypes, IntTypes, FloatTypes, cast_image + +from .extension_to_image_io import extension_to_image_io +from .image_io_index import image_io_index + +def read_image( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + """Read an image file format and convert it to the itk-wasm file format. + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :param pixel_type: Pixel type to cast to. + :type pixel_Type: Optional[PixelTypes] + + :param component_type: Component type to cast to. + :type component_type: Optional[Union[IntTypes, FloatTypes]] + + :return: Output image + :rtype: Image + """ + file_name = Path(serialized_image).name + extension = ''.join(Path(serialized_image).suffixes) + + io = None + if extension in extension_to_image_io: + func = f"{extension_to_image_io[extension]}_read_image" + mod_name = f"itkwasm_image_io_wasi.{func}" + mod = importlib.import_module(mod_name) + io = getattr(mod, func) + else: + for ioname in image_io_index: + func = f"{ioname}_read_image" + mod_name = f"itkwasm_image_io_wasi.{func}" + mod = importlib.import_module(mod_name) + io = getattr(mod, func) + could_read, image = io(serialized_image, information_only=information_only) + if could_read: + if pixel_type or component_type: + image = cast_image(image, pixel_type=pixel_type, component_type=component_type) + return image + + if io is None: + raise RuntimeError(f"Could not find an image reader for {extension}") + + could_read, image = io(serialized_image, information_only=information_only) + if not could_read: + raise RuntimeError(f"Could not read {serialized_image}") + + if pixel_type or component_type: + image = cast_image(image, pixel_type=pixel_type, component_type=component_type) + return image + + +def imread( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + return read_image(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type) + +imread.__doc__ = f"""{read_image.__doc__} + Alias for read_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_png.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_png.py new file mode 100644 index 000000000..11cfe3cf7 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_png.py @@ -0,0 +1,43 @@ +from pathlib import Path + +from itkwasm_image_io_wasi import png_read_image, png_write_image + +from .common import test_input_path, test_output_path + +test_input_file_path = test_input_path / "cthead1.png" +test_output_file_path = test_output_path / "png-test-cthead1.png" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 3 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + +def test_png_read_image(): + could_read, image = png_read_image(test_input_file_path) + assert could_read + verify_image(image) + +def test_png_write_image(): + could_read, image = png_read_image(test_input_file_path) + assert could_read + + use_compression = False + could_write = png_write_image(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = png_read_image(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py new file mode 100644 index 000000000..38c882774 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py @@ -0,0 +1,58 @@ +from pathlib import Path + +from itkwasm import PixelTypes, IntTypes + +from itkwasm_image_io_wasi import read_image, imread + +from .common import test_input_path, test_output_path + +test_input_file_path = test_input_path / "cthead1.png" +test_output_file_path = test_output_path / "read-write-cthead1.png" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 3 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + +def test_read_image(): + image = read_image(test_input_file_path) + verify_image(image) + +def test_read_image_pixel_type(): + image = read_image(test_input_file_path, pixel_type=PixelTypes.Vector) + assert image.imageType.pixelType == "Vector" + +def test_read_image_component_type(): + image = read_image(test_input_file_path, component_type=IntTypes.UInt16) + assert image.imageType.componentType == "uint16" + +def test_imread(): + image = imread(test_input_file_path) + verify_image(image) + +def test_write_image(): + pass + return + could_read, image = png_read_image(test_input_file_path) + assert could_read + + use_compression = False + could_write = png_write_image(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = png_read_image(test_output_file_path) + assert could_read + verify_image(image) diff --git a/packages/image-io/typescript/src/extension-to-image-io.ts b/packages/image-io/typescript/src/extension-to-image-io.ts index a4461ab14..d18d3dab8 100644 --- a/packages/image-io/typescript/src/extension-to-image-io.ts +++ b/packages/image-io/typescript/src/extension-to-image-io.ts @@ -48,6 +48,7 @@ const extensionToImageIo = new Map([ ['vtk', 'vtk'], ['isq', 'scanco'], + ['aim', 'scanco'], ['fdf', 'fdf'], ]) From 871ab831e89df49c0450f1894f3649bf995cffe3 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 22 Oct 2023 21:21:54 -0400 Subject: [PATCH 04/23] test(itkwasm-image-io-wasi): add MetaImage test --- .../tests/test_metaimage.py | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/test_metaimage.py diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_metaimage.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_metaimage.py new file mode 100644 index 000000000..6d9ef47bd --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_metaimage.py @@ -0,0 +1,52 @@ +from pathlib import Path + +from itkwasm_image_io_wasi import meta_read_image, meta_write_image + +from .common import test_input_path, test_output_path + +test_input_file_path = test_input_path / 'brainweb165a10f17.mha' +test_output_file_path = test_output_path / 'meta-image-test-brainweb165a10f17.mha' + +def verify_image(image): + assert image.imageType.dimension == 3 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.origin[2] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.spacing[2] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[0, 2] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.direction[1, 2] == 0.0 + assert image.direction[2, 0] == 0.0 + assert image.direction[2, 1] == 0.0 + assert image.direction[2, 2] == 1.0 + assert image.size[0] == 181 + assert image.size[1] == 217 + assert image.size[2] == 180 + assert image.data.ravel()[0] == 5 + assert image.data.ravel()[1] == 8 + assert image.data.ravel()[2] == 2 + +def test_meta_read_image(): + could_read, image = meta_read_image(test_input_file_path) + assert could_read + verify_image(image) + +def test_meta_write_image(): + could_read, image = meta_read_image(test_input_file_path) + assert could_read + + use_compression = False + could_write = meta_write_image(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = meta_read_image(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file From 2d88004880e200c77792ae9983b108a52af30e80 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 22 Oct 2023 21:38:05 -0400 Subject: [PATCH 05/23] feat(itkwasm-image-io-wasi): add write_image --- .../itkwasm_image_io_wasi/__init__.py | 1 + .../itkwasm_image_io_wasi/write_image.py | 69 +++++++++++++++++++ .../tests/test_read_write_image.py | 22 +++--- 3 files changed, 83 insertions(+), 9 deletions(-) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/write_image.py diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py index 9f8a84c22..287c25999 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/__init__.py @@ -1,6 +1,7 @@ """itkwasm-image-io-wasi: Input and output for scientific and medical image file formats. WASI implementation.""" from .read_image import read_image, imread +from .write_image import write_image, imwrite from .bio_rad_read_image import bio_rad_read_image from .bio_rad_write_image import bio_rad_write_image diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/write_image.py new file mode 100644 index 000000000..2e2da1e60 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/write_image.py @@ -0,0 +1,69 @@ +import os +import importlib +from pathlib import Path +from typing import Optional, Union + +from itkwasm import Image, PixelTypes, IntTypes, FloatTypes, cast_image + +from .extension_to_image_io import extension_to_image_io +from .image_io_index import image_io_index + +def write_image( + image: Image, + serialized_image: os.PathLike, + information_only: bool = False, + use_compression: bool = False, +) -> None: + """Write an itk-wasm Image to an image file format. + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + """ + extension = ''.join(Path(serialized_image).suffixes) + + io = None + if extension in extension_to_image_io: + func = f"{extension_to_image_io[extension]}_write_image" + mod_name = f"itkwasm_image_io_wasi.{func}" + mod = importlib.import_module(mod_name) + io = getattr(mod, func) + else: + for ioname in image_io_index: + func = f"{ioname}_write_image" + mod_name = f"itkwasm_image_io_wasi.{func}" + mod = importlib.import_module(mod_name) + io = getattr(mod, func) + could_write = io(image, serialized_image, information_only=information_only, use_compression=use_compression) + if could_write: + return + + if io is None: + raise RuntimeError(f"Could not find an image writer for {extension}") + + could_write = io(image, serialized_image, information_only=information_only, use_compression=use_compression) + if not could_write: + raise RuntimeError(f"Could not write {serialized_image}") + +def imwrite( + image: Image, + serialized_image: os.PathLike, + information_only: bool = False, + use_compression: bool = False, +) -> None: + return write_image(image, serialized_image, information_only=information_only, use_compression=use_compression) + +imwrite.__doc__ = f"""{write_image.__doc__} + Alias for write_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py index 38c882774..2b50a991c 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py @@ -2,7 +2,7 @@ from itkwasm import PixelTypes, IntTypes -from itkwasm_image_io_wasi import read_image, imread +from itkwasm_image_io_wasi import read_image, imread, write_image, imwrite from .common import test_input_path, test_output_path @@ -44,15 +44,19 @@ def test_imread(): verify_image(image) def test_write_image(): - pass - return - could_read, image = png_read_image(test_input_file_path) - assert could_read + image = read_image(test_input_file_path) + + use_compression = False + write_image(image, test_output_file_path, use_compression=use_compression) + + image = read_image(test_output_file_path) + verify_image(image) + +def test_imwrite(): + image = imread(test_input_file_path) use_compression = False - could_write = png_write_image(image, test_output_file_path, use_compression) - assert could_write + imwrite(image, test_output_file_path, use_compression=use_compression) - could_read, image = png_read_image(test_output_file_path) - assert could_read + image = imread(test_output_file_path) verify_image(image) From a280f80dbc720e8405f4cd024dfac87276020d12 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 22 Oct 2023 21:45:26 -0400 Subject: [PATCH 06/23] test(itkwasm-image-io-wasi): add fdf test --- .../itkwasm-image-io-wasi/tests/test_fdf.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/test_fdf.py diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_fdf.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_fdf.py new file mode 100644 index 000000000..28d527d6f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_fdf.py @@ -0,0 +1,28 @@ +from itkwasm_image_io_wasi import fdf_read_image + +from .common import test_input_path + +test_input_file_path = test_input_path / "test.fdf" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "float32" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 0.15625 + assert image.spacing[1] == 0.17578125 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + +def test_fdf_read_image(): + could_read, image = fdf_read_image(test_input_file_path) + assert could_read + verify_image(image) \ No newline at end of file From 4c1f4932d6e4410f13f836d98161b7f3f4984c78 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 22 Oct 2023 22:37:51 -0400 Subject: [PATCH 07/23] test(itkwasm-image-io-wasi): add lsm test --- .../itkwasm-image-io-wasi/tests/test_lsm.py | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/image-io/python/itkwasm-image-io-wasi/tests/test_lsm.py diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_lsm.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_lsm.py new file mode 100644 index 000000000..59e66b4dd --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_lsm.py @@ -0,0 +1,28 @@ +from itkwasm_image_io_wasi import lsm_read_image + +from .common import test_input_path + +test_input_file_path = test_input_path / "cthead1.lsm" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 4 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0e-8 + assert image.spacing[1] == 1.0e-8 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + +def test_lsm_read_image(): + could_read, image = lsm_read_image(test_input_file_path) + assert could_read + verify_image(image) \ No newline at end of file From 1b0a814371cd871d5c0b062a4645f6c494bdc5b3 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 22 Oct 2023 23:30:32 -0400 Subject: [PATCH 08/23] fix(bindgen): create __init__.py for emscripten package test fix import --- src/bindgen/python/emscripten/emscripten-test-module.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bindgen/python/emscripten/emscripten-test-module.js b/src/bindgen/python/emscripten/emscripten-test-module.js index 4bcb23269..e0fec60f9 100644 --- a/src/bindgen/python/emscripten/emscripten-test-module.js +++ b/src/bindgen/python/emscripten/emscripten-test-module.js @@ -32,6 +32,10 @@ async def test_example(selenium, package_wheel): if (!fs.existsSync(modulePath)) { fs.writeFileSync(modulePath, moduleContent) } + const initPath = path.join(packageDir, 'test', '__init__.py') + if (!fs.existsSync(initPath)) { + fs.writeFileSync(initPath, '') + } } export default emscriptenTestModule From 815d90197479533ea0045a58a5cc4867f9af380c Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sun, 22 Oct 2023 23:48:01 -0400 Subject: [PATCH 09/23] feat(itkwasm-image-io): initial addition --- .../tests/test_read_write_image.py | 2 - .../python/itkwasm-image-io/README.md | 11 +++ .../python/itkwasm-image-io/docs/Makefile | 20 ++++ .../itkwasm-image-io/docs/_static/favicon.png | Bin 0 -> 13605 bytes .../itkwasm-image-io/docs/_static/logo.svg | 1 + .../python/itkwasm-image-io/docs/conf.py | 56 +++++++++++ .../python/itkwasm-image-io/docs/index.md | 35 +++++++ .../python/itkwasm-image-io/docs/make.bat | 35 +++++++ .../itkwasm-image-io/docs/requirements.txt | 8 ++ .../itkwasm_image_io/__init__.py | 91 ++++++++++++++++++ .../itkwasm_image_io/_version.py | 1 + .../itkwasm_image_io/bio_rad_read_image.py | 32 ++++++ .../bio_rad_read_image_async.py | 32 ++++++ .../itkwasm_image_io/bio_rad_write_image.py | 37 +++++++ .../bio_rad_write_image_async.py | 37 +++++++ .../itkwasm_image_io/bmp_read_image.py | 32 ++++++ .../itkwasm_image_io/bmp_read_image_async.py | 32 ++++++ .../itkwasm_image_io/bmp_write_image.py | 37 +++++++ .../itkwasm_image_io/bmp_write_image_async.py | 37 +++++++ .../itkwasm_image_io/fdf_read_image.py | 32 ++++++ .../itkwasm_image_io/fdf_read_image_async.py | 32 ++++++ .../itkwasm_image_io/fdf_write_image.py | 37 +++++++ .../itkwasm_image_io/fdf_write_image_async.py | 37 +++++++ .../itkwasm_image_io/gdcm_read_image.py | 32 ++++++ .../itkwasm_image_io/gdcm_read_image_async.py | 32 ++++++ .../itkwasm_image_io/gdcm_write_image.py | 37 +++++++ .../gdcm_write_image_async.py | 37 +++++++ .../itkwasm_image_io/ge4_read_image.py | 32 ++++++ .../itkwasm_image_io/ge4_read_image_async.py | 32 ++++++ .../itkwasm_image_io/ge4_write_image.py | 37 +++++++ .../itkwasm_image_io/ge4_write_image_async.py | 37 +++++++ .../itkwasm_image_io/ge5_read_image.py | 32 ++++++ .../itkwasm_image_io/ge5_read_image_async.py | 32 ++++++ .../itkwasm_image_io/ge5_write_image.py | 37 +++++++ .../itkwasm_image_io/ge5_write_image_async.py | 37 +++++++ .../itkwasm_image_io/ge_adw_read_image.py | 32 ++++++ .../ge_adw_read_image_async.py | 32 ++++++ .../itkwasm_image_io/ge_adw_write_image.py | 37 +++++++ .../ge_adw_write_image_async.py | 37 +++++++ .../itkwasm_image_io/gipl_read_image.py | 32 ++++++ .../itkwasm_image_io/gipl_read_image_async.py | 32 ++++++ .../itkwasm_image_io/gipl_write_image.py | 37 +++++++ .../gipl_write_image_async.py | 37 +++++++ .../itkwasm_image_io/jpeg_read_image.py | 32 ++++++ .../itkwasm_image_io/jpeg_read_image_async.py | 32 ++++++ .../itkwasm_image_io/jpeg_write_image.py | 37 +++++++ .../jpeg_write_image_async.py | 37 +++++++ .../itkwasm_image_io/lsm_read_image.py | 32 ++++++ .../itkwasm_image_io/lsm_read_image_async.py | 32 ++++++ .../itkwasm_image_io/lsm_write_image.py | 37 +++++++ .../itkwasm_image_io/lsm_write_image_async.py | 37 +++++++ .../itkwasm_image_io/meta_read_image.py | 32 ++++++ .../itkwasm_image_io/meta_read_image_async.py | 32 ++++++ .../itkwasm_image_io/meta_write_image.py | 37 +++++++ .../meta_write_image_async.py | 37 +++++++ .../itkwasm_image_io/mgh_read_image.py | 32 ++++++ .../itkwasm_image_io/mgh_read_image_async.py | 32 ++++++ .../itkwasm_image_io/mgh_write_image.py | 37 +++++++ .../itkwasm_image_io/mgh_write_image_async.py | 37 +++++++ .../itkwasm_image_io/mrc_read_image.py | 32 ++++++ .../itkwasm_image_io/mrc_read_image_async.py | 32 ++++++ .../itkwasm_image_io/mrc_write_image.py | 37 +++++++ .../itkwasm_image_io/mrc_write_image_async.py | 37 +++++++ .../itkwasm_image_io/nifti_read_image.py | 32 ++++++ .../nifti_read_image_async.py | 32 ++++++ .../itkwasm_image_io/nifti_write_image.py | 37 +++++++ .../nifti_write_image_async.py | 37 +++++++ .../itkwasm_image_io/nrrd_read_image.py | 32 ++++++ .../itkwasm_image_io/nrrd_read_image_async.py | 32 ++++++ .../itkwasm_image_io/nrrd_write_image.py | 37 +++++++ .../nrrd_write_image_async.py | 37 +++++++ .../itkwasm_image_io/png_read_image.py | 32 ++++++ .../itkwasm_image_io/png_read_image_async.py | 32 ++++++ .../itkwasm_image_io/png_write_image.py | 37 +++++++ .../itkwasm_image_io/png_write_image_async.py | 37 +++++++ .../itkwasm_image_io/read_image.py | 49 ++++++++++ .../itkwasm_image_io/scanco_read_image.py | 32 ++++++ .../scanco_read_image_async.py | 32 ++++++ .../itkwasm_image_io/scanco_write_image.py | 37 +++++++ .../scanco_write_image_async.py | 37 +++++++ .../itkwasm_image_io/tiff_read_image.py | 32 ++++++ .../itkwasm_image_io/tiff_read_image_async.py | 32 ++++++ .../itkwasm_image_io/tiff_write_image.py | 37 +++++++ .../tiff_write_image_async.py | 37 +++++++ .../itkwasm_image_io/vtk_read_image.py | 32 ++++++ .../itkwasm_image_io/vtk_read_image_async.py | 32 ++++++ .../itkwasm_image_io/vtk_write_image.py | 37 +++++++ .../itkwasm_image_io/vtk_write_image_async.py | 37 +++++++ .../itkwasm_image_io/wasm_read_image.py | 32 ++++++ .../itkwasm_image_io/wasm_read_image_async.py | 32 ++++++ .../itkwasm_image_io/wasm_write_image.py | 37 +++++++ .../wasm_write_image_async.py | 37 +++++++ .../itkwasm_image_io/wasm_zstd_read_image.py | 32 ++++++ .../wasm_zstd_read_image_async.py | 32 ++++++ .../itkwasm_image_io/wasm_zstd_write_image.py | 37 +++++++ .../wasm_zstd_write_image_async.py | 37 +++++++ .../itkwasm_image_io/write_image.py | 43 +++++++++ .../python/itkwasm-image-io/pyproject.toml | 61 ++++++++++++ .../python/itkwasm-image-io/tests/__init__.py | 0 .../python/itkwasm-image-io/tests/common.py | 6 ++ .../python/itkwasm-image-io/tests/test_png.py | 41 ++++++++ .../tests/test_read_write_image.py | 62 ++++++++++++ 102 files changed, 3418 insertions(+), 2 deletions(-) create mode 100644 packages/image-io/python/itkwasm-image-io/README.md create mode 100644 packages/image-io/python/itkwasm-image-io/docs/Makefile create mode 100644 packages/image-io/python/itkwasm-image-io/docs/_static/favicon.png create mode 100644 packages/image-io/python/itkwasm-image-io/docs/_static/logo.svg create mode 100644 packages/image-io/python/itkwasm-image-io/docs/conf.py create mode 100644 packages/image-io/python/itkwasm-image-io/docs/index.md create mode 100644 packages/image-io/python/itkwasm-image-io/docs/make.bat create mode 100644 packages/image-io/python/itkwasm-image-io/docs/requirements.txt create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py create mode 100644 packages/image-io/python/itkwasm-image-io/pyproject.toml create mode 100644 packages/image-io/python/itkwasm-image-io/tests/__init__.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/common.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/test_png.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/test_read_write_image.py diff --git a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py index 2b50a991c..96d8dd653 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/tests/test_read_write_image.py @@ -1,5 +1,3 @@ -from pathlib import Path - from itkwasm import PixelTypes, IntTypes from itkwasm_image_io_wasi import read_image, imread, write_image, imwrite diff --git a/packages/image-io/python/itkwasm-image-io/README.md b/packages/image-io/python/itkwasm-image-io/README.md new file mode 100644 index 000000000..5836e7c60 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/README.md @@ -0,0 +1,11 @@ +# itkwasm-image-io + +[![PyPI version](https://badge.fury.io/py/itkwasm-image-io.svg)](https://badge.fury.io/py/itkwasm-image-io) + +Input and output for scientific and medical image file formats. + +## Installation + +```sh +pip install itkwasm-image-io +``` diff --git a/packages/image-io/python/itkwasm-image-io/docs/Makefile b/packages/image-io/python/itkwasm-image-io/docs/Makefile new file mode 100644 index 000000000..d4bb2cbb9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/packages/image-io/python/itkwasm-image-io/docs/_static/favicon.png b/packages/image-io/python/itkwasm-image-io/docs/_static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..bd1e535c6d807ba2313cae8722a4944bb28d46af GIT binary patch literal 13605 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 literal 0 HcmV?d00001 diff --git a/packages/image-io/python/itkwasm-image-io/docs/_static/logo.svg b/packages/image-io/python/itkwasm-image-io/docs/_static/logo.svg new file mode 100644 index 000000000..669a445ed --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/docs/_static/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/docs/conf.py b/packages/image-io/python/itkwasm-image-io/docs/conf.py new file mode 100644 index 000000000..2244708cc --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/docs/conf.py @@ -0,0 +1,56 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +from datetime import date + +project = 'itkwasm-image-io' +copyright = f'{date.today().year}, NumFOCUS' +author = 'Insight Software Consortium' + +extensions = [ + 'sphinx.ext.autosummary', + 'autodoc2', + 'myst_parser', + 'sphinx.ext.intersphinx', + 'sphinx_copybutton', + 'sphinxext.opengraph', + 'sphinx_design', +] + +myst_enable_extensions = ["colon_fence", "fieldlist"] + +templates_path = ['_templates'] +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +autodoc2_packages = [ + { + "path": "../itkwasm_image_io", + "exclude_files": ["_version.py"], + }, +] +autodoc2_render_plugin = "myst" + +intersphinx_mapping = { + "python": ("https://docs.python.org/3/", None), + "numpy": ("https://numpy.org/doc/stable", None), + "itkwasm": ("https://itkwasm.readthedocs.io/en/latest/", None), +} + +html_theme = 'furo' +html_static_path = ['_static'] +html_logo = "_static/logo.svg" +html_favicon = "_static/favicon.png" +html_title = f"{project}" + +# Furo options +html_theme_options = { + "top_of_page_button": "edit", + "source_repository": "https://github.com/InsightSoftwareConsortium/itk-wasm", + "source_branch": "main", + "source_directory": "docs", +} \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/docs/index.md b/packages/image-io/python/itkwasm-image-io/docs/index.md new file mode 100644 index 000000000..844a01e3d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/docs/index.md @@ -0,0 +1,35 @@ +itkwasm-image-io +======= + +> Input and output for scientific and medical image file formats. + +[![itkwasm-image-io version](https://badge.fury.io/py/itkwasm_image_io.svg)](https://pypi.org/project/itkwasm_image_io/) + +## Installation + +::::{tab-set} + +:::{tab-item} System +```shell +pip install itkwasm-image-io +``` +::: + +:::{tab-item} Browser +In Pyodide, e.g. the [Pyodide REPL](https://pyodide.org/en/stable/console.html) or [JupyterLite](https://jupyterlite.readthedocs.io/en/latest/try/lab), + +```python +import micropip +await micropip.install('itkwasm-image-io') +::: + +:::: + +```{toctree} +:hidden: +:maxdepth: 3 +:caption: 📖 Reference + +apidocs/index.rst +itkwasm docs +``` \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/docs/make.bat b/packages/image-io/python/itkwasm-image-io/docs/make.bat new file mode 100644 index 000000000..32bb24529 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=. +set BUILDDIR=_build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/packages/image-io/python/itkwasm-image-io/docs/requirements.txt b/packages/image-io/python/itkwasm-image-io/docs/requirements.txt new file mode 100644 index 000000000..0c8041793 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/docs/requirements.txt @@ -0,0 +1,8 @@ +astroid<3 +sphinx +furo +sphinx-autodoc2 +myst-parser +sphinx-copybutton +sphinxext-opengraph +sphinx-design diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py new file mode 100644 index 000000000..3f2b7bc42 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py @@ -0,0 +1,91 @@ +"""itkwasm-image-io: Input and output for scientific and medical image file formats.""" + +from .read_image import read_image, imread +from .write_image import write_image, imwrite + +from .bio_rad_read_image_async import bio_rad_read_image_async +from .bio_rad_read_image import bio_rad_read_image +from .bio_rad_write_image_async import bio_rad_write_image_async +from .bio_rad_write_image import bio_rad_write_image +from .bmp_read_image_async import bmp_read_image_async +from .bmp_read_image import bmp_read_image +from .bmp_write_image_async import bmp_write_image_async +from .bmp_write_image import bmp_write_image +from .fdf_read_image_async import fdf_read_image_async +from .fdf_read_image import fdf_read_image +from .fdf_write_image_async import fdf_write_image_async +from .fdf_write_image import fdf_write_image +from .gdcm_read_image_async import gdcm_read_image_async +from .gdcm_read_image import gdcm_read_image +from .gdcm_write_image_async import gdcm_write_image_async +from .gdcm_write_image import gdcm_write_image +from .ge_adw_read_image_async import ge_adw_read_image_async +from .ge_adw_read_image import ge_adw_read_image +from .ge_adw_write_image_async import ge_adw_write_image_async +from .ge_adw_write_image import ge_adw_write_image +from .ge4_read_image_async import ge4_read_image_async +from .ge4_read_image import ge4_read_image +from .ge4_write_image_async import ge4_write_image_async +from .ge4_write_image import ge4_write_image +from .ge5_read_image_async import ge5_read_image_async +from .ge5_read_image import ge5_read_image +from .ge5_write_image_async import ge5_write_image_async +from .ge5_write_image import ge5_write_image +from .gipl_read_image_async import gipl_read_image_async +from .gipl_read_image import gipl_read_image +from .gipl_write_image_async import gipl_write_image_async +from .gipl_write_image import gipl_write_image +from .jpeg_read_image_async import jpeg_read_image_async +from .jpeg_read_image import jpeg_read_image +from .jpeg_write_image_async import jpeg_write_image_async +from .jpeg_write_image import jpeg_write_image +from .lsm_read_image_async import lsm_read_image_async +from .lsm_read_image import lsm_read_image +from .lsm_write_image_async import lsm_write_image_async +from .lsm_write_image import lsm_write_image +from .meta_read_image_async import meta_read_image_async +from .meta_read_image import meta_read_image +from .meta_write_image_async import meta_write_image_async +from .meta_write_image import meta_write_image +from .mgh_read_image_async import mgh_read_image_async +from .mgh_read_image import mgh_read_image +from .mgh_write_image_async import mgh_write_image_async +from .mgh_write_image import mgh_write_image +from .mrc_read_image_async import mrc_read_image_async +from .mrc_read_image import mrc_read_image +from .mrc_write_image_async import mrc_write_image_async +from .mrc_write_image import mrc_write_image +from .nifti_read_image_async import nifti_read_image_async +from .nifti_read_image import nifti_read_image +from .nifti_write_image_async import nifti_write_image_async +from .nifti_write_image import nifti_write_image +from .nrrd_read_image_async import nrrd_read_image_async +from .nrrd_read_image import nrrd_read_image +from .nrrd_write_image_async import nrrd_write_image_async +from .nrrd_write_image import nrrd_write_image +from .png_read_image_async import png_read_image_async +from .png_read_image import png_read_image +from .png_write_image_async import png_write_image_async +from .png_write_image import png_write_image +from .scanco_read_image_async import scanco_read_image_async +from .scanco_read_image import scanco_read_image +from .scanco_write_image_async import scanco_write_image_async +from .scanco_write_image import scanco_write_image +from .tiff_read_image_async import tiff_read_image_async +from .tiff_read_image import tiff_read_image +from .tiff_write_image_async import tiff_write_image_async +from .tiff_write_image import tiff_write_image +from .vtk_read_image_async import vtk_read_image_async +from .vtk_read_image import vtk_read_image +from .vtk_write_image_async import vtk_write_image_async +from .vtk_write_image import vtk_write_image +from .wasm_read_image_async import wasm_read_image_async +from .wasm_read_image import wasm_read_image +from .wasm_write_image_async import wasm_write_image_async +from .wasm_write_image import wasm_write_image +from .wasm_zstd_read_image_async import wasm_zstd_read_image_async +from .wasm_zstd_read_image import wasm_zstd_read_image +from .wasm_zstd_write_image_async import wasm_zstd_write_image_async +from .wasm_zstd_write_image import wasm_zstd_write_image + +from ._version import __version__ diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py new file mode 100644 index 000000000..493f7415d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py @@ -0,0 +1 @@ +__version__ = "0.3.0" diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image.py new file mode 100644 index 000000000..5a2a82b23 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def bio_rad_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "bio_rad_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image_async.py new file mode 100644 index 000000000..10f4b95b7 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def bio_rad_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "bio_rad_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image.py new file mode 100644 index 000000000..ade6973bd --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def bio_rad_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "bio_rad_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image_async.py new file mode 100644 index 000000000..128651e0c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bio_rad_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def bio_rad_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "bio_rad_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image.py new file mode 100644 index 000000000..620b8edc8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def bmp_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "bmp_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image_async.py new file mode 100644 index 000000000..c74c74734 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def bmp_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "bmp_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image.py new file mode 100644 index 000000000..048ffc60d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def bmp_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "bmp_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image_async.py new file mode 100644 index 000000000..36a0f687c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/bmp_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def bmp_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "bmp_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image.py new file mode 100644 index 000000000..9f2d0278a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def fdf_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "fdf_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image_async.py new file mode 100644 index 000000000..b52090ad5 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def fdf_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "fdf_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image.py new file mode 100644 index 000000000..ef74fbe24 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def fdf_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "fdf_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image_async.py new file mode 100644 index 000000000..7afcc16b6 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/fdf_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def fdf_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "fdf_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image.py new file mode 100644 index 000000000..a87b1f3ec --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def gdcm_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "gdcm_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image_async.py new file mode 100644 index 000000000..b883fafc1 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def gdcm_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "gdcm_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image.py new file mode 100644 index 000000000..1ae274872 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def gdcm_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "gdcm_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image_async.py new file mode 100644 index 000000000..186085509 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gdcm_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def gdcm_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "gdcm_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image.py new file mode 100644 index 000000000..b37a0ce0c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def ge4_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "ge4_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image_async.py new file mode 100644 index 000000000..f963d6701 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def ge4_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "ge4_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image.py new file mode 100644 index 000000000..6ba609f6a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def ge4_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "ge4_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image_async.py new file mode 100644 index 000000000..3dd30e148 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge4_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def ge4_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "ge4_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image.py new file mode 100644 index 000000000..d03e8b67a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def ge5_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "ge5_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image_async.py new file mode 100644 index 000000000..32f36b7f9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def ge5_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "ge5_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image.py new file mode 100644 index 000000000..f56b94c61 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def ge5_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "ge5_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image_async.py new file mode 100644 index 000000000..68b764cf5 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge5_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def ge5_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "ge5_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image.py new file mode 100644 index 000000000..39b0e953d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def ge_adw_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "ge_adw_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image_async.py new file mode 100644 index 000000000..6ff784f5c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def ge_adw_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "ge_adw_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image.py new file mode 100644 index 000000000..66d73c664 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def ge_adw_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "ge_adw_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image_async.py new file mode 100644 index 000000000..18fbbc4ec --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/ge_adw_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def ge_adw_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "ge_adw_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image.py new file mode 100644 index 000000000..e8e643f19 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def gipl_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "gipl_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image_async.py new file mode 100644 index 000000000..346e0f3b6 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def gipl_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "gipl_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image.py new file mode 100644 index 000000000..ea7f4744e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def gipl_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "gipl_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image_async.py new file mode 100644 index 000000000..90fc85fe0 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/gipl_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def gipl_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "gipl_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image.py new file mode 100644 index 000000000..fc00f6f9f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def jpeg_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "jpeg_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image_async.py new file mode 100644 index 000000000..760fd0016 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def jpeg_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "jpeg_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image.py new file mode 100644 index 000000000..5ae0ad9bc --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def jpeg_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "jpeg_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image_async.py new file mode 100644 index 000000000..e4d048944 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/jpeg_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def jpeg_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "jpeg_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image.py new file mode 100644 index 000000000..19ee224cb --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def lsm_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "lsm_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image_async.py new file mode 100644 index 000000000..c40f2b7ea --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def lsm_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "lsm_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image.py new file mode 100644 index 000000000..633cb4ffe --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def lsm_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "lsm_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image_async.py new file mode 100644 index 000000000..3f3db20c7 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/lsm_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def lsm_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "lsm_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image.py new file mode 100644 index 000000000..95acfb0dc --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def meta_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "meta_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image_async.py new file mode 100644 index 000000000..07552b658 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def meta_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "meta_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image.py new file mode 100644 index 000000000..51cddcf30 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def meta_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "meta_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image_async.py new file mode 100644 index 000000000..1a347f336 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/meta_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def meta_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "meta_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image.py new file mode 100644 index 000000000..1edfc58e8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def mgh_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "mgh_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image_async.py new file mode 100644 index 000000000..3a2ebd679 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def mgh_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "mgh_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image.py new file mode 100644 index 000000000..c4c0cc207 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def mgh_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "mgh_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image_async.py new file mode 100644 index 000000000..707ee8839 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mgh_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def mgh_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "mgh_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image.py new file mode 100644 index 000000000..bdddf2376 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def mrc_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "mrc_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image_async.py new file mode 100644 index 000000000..3da1d6274 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def mrc_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "mrc_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image.py new file mode 100644 index 000000000..37a5ea666 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def mrc_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "mrc_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image_async.py new file mode 100644 index 000000000..eb74db1ce --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/mrc_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def mrc_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "mrc_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image.py new file mode 100644 index 000000000..ebb55f904 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def nifti_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "nifti_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image_async.py new file mode 100644 index 000000000..0133edcd0 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def nifti_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "nifti_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image.py new file mode 100644 index 000000000..78e1b2fee --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def nifti_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "nifti_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image_async.py new file mode 100644 index 000000000..0898298f9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nifti_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def nifti_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "nifti_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image.py new file mode 100644 index 000000000..d4e1deb13 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def nrrd_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "nrrd_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image_async.py new file mode 100644 index 000000000..8613c00ff --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def nrrd_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "nrrd_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image.py new file mode 100644 index 000000000..97be2ea10 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def nrrd_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "nrrd_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image_async.py new file mode 100644 index 000000000..2ca2027df --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/nrrd_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def nrrd_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "nrrd_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image.py new file mode 100644 index 000000000..1912873b8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def png_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "png_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image_async.py new file mode 100644 index 000000000..68a767aab --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def png_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "png_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image.py new file mode 100644 index 000000000..9d96e8307 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def png_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "png_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image_async.py new file mode 100644 index 000000000..5ed264c53 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/png_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def png_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "png_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image.py new file mode 100644 index 000000000..85e318ed5 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image.py @@ -0,0 +1,49 @@ +import os +from typing import Optional, Union + +from itkwasm import ( + environment_dispatch, + Image, + PixelTypes, + IntTypes, + FloatTypes, +) + +def read_image( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :param pixel_type: Pixel type to cast to. + :type pixel_Type: Optional[PixelTypes] + + :param component_type: Component type to cast to. + :type component_type: Optional[Union[IntTypes, FloatTypes]] + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "read_image") + output = func(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type) + return output + +def imread( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + return read_image(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type) + +imread.__doc__ = f"""{read_image.__doc__} + Alias for read_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image.py new file mode 100644 index 000000000..79a606cf9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def scanco_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "scanco_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image_async.py new file mode 100644 index 000000000..eb6d1e198 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def scanco_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "scanco_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image.py new file mode 100644 index 000000000..1bbe2cea1 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def scanco_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "scanco_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image_async.py new file mode 100644 index 000000000..a4c570c35 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/scanco_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def scanco_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "scanco_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image.py new file mode 100644 index 000000000..e627995f3 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def tiff_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "tiff_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image_async.py new file mode 100644 index 000000000..217e92310 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def tiff_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "tiff_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image.py new file mode 100644 index 000000000..c85fa3ba3 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def tiff_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "tiff_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image_async.py new file mode 100644 index 000000000..c85246777 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/tiff_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def tiff_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "tiff_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image.py new file mode 100644 index 000000000..08ae17ced --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def vtk_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "vtk_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image_async.py new file mode 100644 index 000000000..2517aa805 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def vtk_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "vtk_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image.py new file mode 100644 index 000000000..ada63126c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def vtk_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "vtk_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image_async.py new file mode 100644 index 000000000..b5044f017 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/vtk_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def vtk_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "vtk_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image.py new file mode 100644 index 000000000..7bd648d64 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def wasm_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "wasm_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image_async.py new file mode 100644 index 000000000..efbd3fd1a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def wasm_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "wasm_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image.py new file mode 100644 index 000000000..68b73e04d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def wasm_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "wasm_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image_async.py new file mode 100644 index 000000000..33bcc793a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def wasm_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "wasm_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image.py new file mode 100644 index 000000000..499f62727 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +def wasm_zstd_read_image( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "wasm_zstd_read_image") + output = func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image_async.py new file mode 100644 index 000000000..ba84a3761 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_read_image_async.py @@ -0,0 +1,32 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + BinaryFile, + Image, +) + +async def wasm_zstd_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "wasm_zstd_read_image_async") + output = await func(serialized_image, information_only=information_only) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image.py new file mode 100644 index 000000000..53a0f583e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +def wasm_zstd_write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "wasm_zstd_write_image") + output = func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image_async.py new file mode 100644 index 000000000..28c1e2ad6 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/wasm_zstd_write_image_async.py @@ -0,0 +1,37 @@ +# Generated file. Do not edit. + +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, + BinaryFile, +) + +async def wasm_zstd_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + func = environment_dispatch("itkwasm_image_io", "wasm_zstd_write_image_async") + output = await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return output diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py new file mode 100644 index 000000000..692ec5428 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py @@ -0,0 +1,43 @@ +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, +) + +def write_image( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> None: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + """ + func = environment_dispatch("itkwasm_image_io", "png_write_image") + func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return + +def imwrite( + image: Image, + serialized_image: os.PathLike, + information_only: bool = False, + use_compression: bool = False, +) -> None: + return write_image(image, serialized_image, information_only=information_only, use_compression=use_compression) + +imwrite.__doc__ = f"""{write_image.__doc__} + Alias for write_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/pyproject.toml b/packages/image-io/python/itkwasm-image-io/pyproject.toml new file mode 100644 index 000000000..eb0eee3ec --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/pyproject.toml @@ -0,0 +1,61 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "itkwasm-image-io" +readme = "README.md" +license = "Apache-2.0" +dynamic = ["version"] +description = "Input and output for scientific and medical image file formats." +classifiers = [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: C++", + "Environment :: WebAssembly", + "Environment :: WebAssembly :: Emscripten", + "Environment :: WebAssembly :: WASI", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +keywords = [ + "itkwasm", + "webassembly", + "wasi", + "emscripten", +] + +requires-python = ">=3.8" +dependencies = [ + "itkwasm >= 1.0.b131", + "itkwasm-image-io-wasi; sys_platform != \"emscripten\"", + "itkwasm-image-io-emscripten; sys_platform == \"emscripten\"", + +] + +[tool.hatch.version] +path = "itkwasm_image_io/_version.py" + +[tool.hatch.envs.default] +dependencies = [ + "pytest", +] + +[project.urls] +Home = "https://github.com/InsightSoftwareConsortium/itk-wasm" +Source = "https://github.com/InsightSoftwareConsortium/itk-wasm" + +[tool.hatch.envs.default.scripts] +test = "pytest" + + +[tool.hatch.build] +exclude = [ + "/examples", +] diff --git a/packages/image-io/python/itkwasm-image-io/tests/__init__.py b/packages/image-io/python/itkwasm-image-io/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/packages/image-io/python/itkwasm-image-io/tests/common.py b/packages/image-io/python/itkwasm-image-io/tests/common.py new file mode 100644 index 000000000..caf5bf5d9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/common.py @@ -0,0 +1,6 @@ +from pathlib import Path + +test_input_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "input" +test_baseline_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "baseline" +test_output_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "python" +test_output_path.mkdir(parents=True, exist_ok=True) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/tests/test_png.py b/packages/image-io/python/itkwasm-image-io/tests/test_png.py new file mode 100644 index 000000000..4500b5608 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/test_png.py @@ -0,0 +1,41 @@ +from itkwasm_image_io import png_read_image, png_write_image + +from .common import test_input_path, test_output_path + +test_input_file_path = test_input_path / "cthead1.png" +test_output_file_path = test_output_path / "png-test-cthead1.png" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 3 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + +def test_png_read_image(): + could_read, image = png_read_image(test_input_file_path) + assert could_read + verify_image(image) + +def test_png_write_image(): + could_read, image = png_read_image(test_input_file_path) + assert could_read + + use_compression = False + could_write = png_write_image(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = png_read_image(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/tests/test_read_write_image.py b/packages/image-io/python/itkwasm-image-io/tests/test_read_write_image.py new file mode 100644 index 000000000..f38adfdb7 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/test_read_write_image.py @@ -0,0 +1,62 @@ +from pathlib import Path + +from itkwasm import PixelTypes, IntTypes + +from itkwasm_image_io import read_image, imread, write_image, imwrite + +from .common import test_input_path, test_output_path + +test_input_file_path = test_input_path / "cthead1.png" +test_output_file_path = test_output_path / "read-write-cthead1.png" + +def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 3 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + +def test_read_image(): + image = read_image(test_input_file_path) + verify_image(image) + +def test_read_image_pixel_type(): + image = read_image(test_input_file_path, pixel_type=PixelTypes.Vector) + assert image.imageType.pixelType == "Vector" + +def test_read_image_component_type(): + image = read_image(test_input_file_path, component_type=IntTypes.UInt16) + assert image.imageType.componentType == "uint16" + +def test_imread(): + image = imread(test_input_file_path) + verify_image(image) + +def test_write_image(): + image = read_image(test_input_file_path) + + use_compression = False + write_image(image, test_output_file_path, use_compression=use_compression) + + image = read_image(test_output_file_path) + verify_image(image) + +def test_imwrite(): + image = imread(test_input_file_path) + + use_compression = False + imwrite(image, test_output_file_path, use_compression=use_compression) + + image = imread(test_output_file_path) + verify_image(image) From 67b6cc8c265188e36f5e47f13c9a56cce0efa39a Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 3 Nov 2023 22:39:17 -0400 Subject: [PATCH 10/23] build(web-workers): correct min web worker bundle output path --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 981167f47..ad0bfcec1 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "build:tscWorkersModuleLoader": "tsc --types --lib es2017,webworker --rootDir ./src/ --outDir ./dist/ --moduleResolution node --target es2017 --module es2020 --strict --forceConsistentCasingInFileNames --declaration ./src/core/internal/loadEmscriptenModuleWebWorker.ts", "build:tscWebWorkers": "tsc -p ./tsconfigWebWorkers.json", "build:workerBundle": "esbuild --bundle --format=esm --outfile=./dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js ./dist/core/web-workers/itk-wasm-pipeline.worker.js", - "build:workerMinBundle": "esbuild --minify --bundle --format=esm --outfile=./dist/web-workers/bundles/pipeline.min.worker.js ./dist/core/web-workers/itk-wasm-pipeline.worker.js", + "build:workerMinBundle": "esbuild --minify --bundle --format=esm --outfile=./dist/core/web-workers/bundles/itk-wasm-pipeline.min.worker.js ./dist/core/web-workers/itk-wasm-pipeline.worker.js", "build:webpack": "webpack --mode production --progress --color && webpack --mode development --progress --color", "build:emscripten": "node ./src/build-emscripten.js", "build:emscripten:compress-stringify": "node ./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build build ", From 0d17b797c6668da575129267d463f8f95f4b5e23 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 3 Nov 2023 23:44:53 -0400 Subject: [PATCH 11/23] build(image-io): switch from rollup to esbuild for bundling Node workaround per: https://github.com/evanw/esbuild/pull/2067 --- packages/image-io/typescript/package.json | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json index 49c144e5b..5e083eced 100644 --- a/packages/image-io/typescript/package.json +++ b/packages/image-io/typescript/package.json @@ -24,8 +24,8 @@ "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", - "build:node": "rollup -c ./build/rollup.node.config.js", - "build:browser": "rollup -c ./build/rollup.browser.config.js", + "build:node": "esbuild --bundle --format=esm --banner:js=\"import { createRequire } from 'module';const require = createRequire(import.meta.url);\" --platform=node --outfile=./dist/index-node.js ./src/index-node.ts", + "build:browser": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/ && esbuild --bundle --format=esm --outfile=./dist/index.js ./src/index.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" @@ -39,26 +39,15 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.126" + "itk-wasm": "^1.0.0-b.152" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.0", - "@rollup/plugin-typescript": "^11.1.1", "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", "ava": "^5.3.1", "cypress": "^13.3.0", - "debug": "^4.3.4", - "rollup": "^3.9.0", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-ignore": "^1.0.10", - "rollup-plugin-polyfill-node": "^0.12.0", + "esbuild": "^0.19.5", "shx": "^0.3.4", - "supports-color": "^9.3.1", - "tslib": "^2.5.2", "typescript": "^5.0.4", "vite": "^4.3.3", "vite-plugin-static-copy": "^0.14.0" From eced03606fb0526d9c7a2002a59a49635727be16 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sat, 4 Nov 2023 09:28:43 -0400 Subject: [PATCH 12/23] build(image-io): build index-worker-embedded.js --- packages/image-io/typescript/package.json | 3 ++- packages/image-io/typescript/src/index-worker-embedded.ts | 5 +++++ packages/image-io/typescript/src/index.ts | 1 - packages/image-io/typescript/tsconfig.json | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 packages/image-io/typescript/src/index-worker-embedded.ts diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json index 5e083eced..96b9d3bf4 100644 --- a/packages/image-io/typescript/package.json +++ b/packages/image-io/typescript/package.json @@ -23,9 +23,10 @@ "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", + "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:browser:workerEmbedded && npm run build:demo", "build:node": "esbuild --bundle --format=esm --banner:js=\"import { createRequire } from 'module';const require = createRequire(import.meta.url);\" --platform=node --outfile=./dist/index-node.js ./src/index-node.ts", "build:browser": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/ && esbuild --bundle --format=esm --outfile=./dist/index.js ./src/index.ts", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/index-worker-embedded.js ./src/index-worker-embedded.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" diff --git a/packages/image-io/typescript/src/index-worker-embedded.ts b/packages/image-io/typescript/src/index-worker-embedded.ts new file mode 100644 index 000000000..c9d87a447 --- /dev/null +++ b/packages/image-io/typescript/src/index-worker-embedded.ts @@ -0,0 +1,5 @@ +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' \ No newline at end of file diff --git a/packages/image-io/typescript/src/index.ts b/packages/image-io/typescript/src/index.ts index 6698a98c7..0e982eb32 100644 --- a/packages/image-io/typescript/src/index.ts +++ b/packages/image-io/typescript/src/index.ts @@ -1,4 +1,3 @@ - export * from './pipelines-base-url.js' export * from './pipeline-worker-url.js' diff --git a/packages/image-io/typescript/tsconfig.json b/packages/image-io/typescript/tsconfig.json index 4eba4b8ec..9864b8178 100644 --- a/packages/image-io/typescript/tsconfig.json +++ b/packages/image-io/typescript/tsconfig.json @@ -19,5 +19,6 @@ "emitDeclarationOnly": true, "declarationDir": "dist/" }, - "include": ["src/*.ts"] + "include": ["src/*.ts"], + "exclude": ["src/index-worker-embedded.ts"] } From 40c5d62b163504d6c07d2d5fb8ad74ed2e19feed Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Fri, 13 Oct 2023 11:19:18 -0400 Subject: [PATCH 13/23] refactor(bindgen): setPipelineWorkerUrl to null by default Use the app's bundler's support for the worker by default. No longer necessary via #970 Improve image-io testing speed via: https://dev.to/noriste/speed-up-e2e-tests-for-vite-based-apps-3k4l Resolve library worker bundling per: https://medium.com/adevinta-tech-blog/introducing-web-workers-to-improve-subito-it-performance-part-2-92bcfed8a62 Vite does not support pre-bundling of web workers in dependencies, so we have to add packages to optimizeDeps.exclude. https://github.com/gkjohnson/three-gpu-pathtracer/issues/355#issuecomment-1402083204 Some updates in compare-images. Further updates to packages in follow-up commits. --- package.json | 18 +- .../_version.py | 2 +- .../js_package.py | 2 +- .../pyproject.toml | 4 +- .../itkwasm_compare_images_wasi/_version.py | 2 +- .../itkwasm_compare_images/_version.py | 2 +- packages/compare-images/typescript/README.md | 61 ++-- .../typescript/build/rollup.browser.config.js | 32 +- .../typescript/build/rollup.node.config.js | 6 +- .../typescript/build/vite.config.js | 8 +- .../typescript/cypress.config.ts | 2 +- .../compare-images/typescript/package.json | 20 +- .../src/compare-double-images-node.ts | 2 +- .../typescript/src/compare-double-images.ts | 4 +- .../compare-images/typescript/src/index.ts | 1 - .../typescript/src/itkConfig.js | 11 - .../typescript/src/vector-magnitude-node.ts | 3 +- .../typescript/src/vector-magnitude.ts | 3 +- .../compare-double-images-controller.ts | 18 +- .../demo-app/compare-images-controller.ts | 16 +- .../typescript/test/browser/demo-app/index.ts | 4 +- .../demo-app/vector-magnitude-controller.ts | 12 +- .../test/node/compare-double-images-test.js | 10 +- .../test/node/compare-images-test.js | 12 +- .../_version.py | 2 +- .../_version.py | 2 +- .../wasm_modules/compress-stringify.wasi.wasm | Bin 1005042 -> 1026109 bytes .../parse-string-decompress.wasi.wasm | Bin 685373 -> 754198 bytes .../itkwasm_compress_stringify/_version.py | 2 +- .../typescript/build/vite.config.js | 1 - .../typescript/cypress.config.ts | 1 + .../typescript/package-lock.json | 322 +++++++++--------- .../typescript/package.json | 10 +- .../typescript/src/compress-stringify-node.ts | 3 +- .../typescript/src/compress-stringify.ts | 3 +- .../typescript/src/index.ts | 1 - .../src/parse-string-decompress-node.ts | 3 +- .../typescript/src/parse-string-decompress.ts | 3 +- .../demo-app/compress-stringify-controller.ts | 2 +- .../typescript/test/browser/demo-app/index.ts | 5 +- .../parse-string-decompress-controller.ts | 2 +- .../itkwasm_dicom_emscripten/_version.py | 2 +- .../itkwasm_dicom_wasi/_version.py | 2 +- .../itkwasm-dicom/itkwasm_dicom/_version.py | 2 +- .../dicom/typescript/build/vite.config.js | 1 - packages/dicom/typescript/package.json | 6 +- .../apply-presentation-state-to-image-node.ts | 3 +- .../src/apply-presentation-state-to-image.ts | 3 +- .../src/read-dicom-encapsulated-pdf-node.ts | 3 +- .../src/read-dicom-encapsulated-pdf.ts | 3 +- .../src/read-image-dicom-file-series-node.ts | 3 +- .../src/structured-report-to-html-node.ts | 3 +- .../src/structured-report-to-html.ts | 3 +- .../src/structured-report-to-text-node.ts | 3 +- .../src/structured-report-to-text.ts | 3 +- ...-presentation-state-to-image-controller.ts | 8 +- .../typescript/test/browser/demo-app/index.ts | 5 +- .../demo-app/read-dicom-tags-controller.ts | 2 +- .../structured-report-to-text-controller.ts | 2 +- packages/image-io/typescript/.npmignore | 3 +- packages/image-io/typescript/README.md | 270 ++++++++++++++- .../typescript/build/rollup.browser.config.js | 32 +- .../typescript/build/rollup.node.config.js | 6 +- .../build/vite-rollup-watch.config.ts | 24 ++ .../image-io/typescript/build/vite.config.js | 39 ++- .../image-io/typescript/cypress.config.ts | 3 +- .../image-io/typescript/cypress/e2e/common.ts | 2 +- packages/image-io/typescript/package.json | 37 +- .../typescript/src/bio-rad-read-image-node.ts | 3 +- .../typescript/src/bio-rad-read-image.ts | 3 +- .../src/bio-rad-write-image-node.ts | 3 +- .../typescript/src/bio-rad-write-image.ts | 3 +- .../typescript/src/bmp-read-image-node.ts | 3 +- .../image-io/typescript/src/bmp-read-image.ts | 3 +- .../typescript/src/bmp-write-image-node.ts | 3 +- .../typescript/src/bmp-write-image.ts | 3 +- .../typescript/src/fdf-read-image-node.ts | 3 +- .../image-io/typescript/src/fdf-read-image.ts | 3 +- .../typescript/src/fdf-write-image-node.ts | 3 +- .../typescript/src/fdf-write-image.ts | 3 +- .../typescript/src/gdcm-read-image-node.ts | 3 +- .../typescript/src/gdcm-read-image.ts | 3 +- .../typescript/src/gdcm-write-image-node.ts | 3 +- .../typescript/src/gdcm-write-image.ts | 3 +- .../typescript/src/ge-adw-read-image-node.ts | 3 +- .../typescript/src/ge-adw-read-image.ts | 3 +- .../typescript/src/ge-adw-write-image-node.ts | 3 +- .../typescript/src/ge-adw-write-image.ts | 3 +- .../typescript/src/ge4-read-image-node.ts | 3 +- .../image-io/typescript/src/ge4-read-image.ts | 3 +- .../typescript/src/ge4-write-image-node.ts | 3 +- .../typescript/src/ge4-write-image.ts | 3 +- .../typescript/src/ge5-read-image-node.ts | 3 +- .../image-io/typescript/src/ge5-read-image.ts | 3 +- .../typescript/src/ge5-write-image-node.ts | 3 +- .../typescript/src/ge5-write-image.ts | 3 +- .../typescript/src/gipl-read-image-node.ts | 3 +- .../typescript/src/gipl-read-image.ts | 3 +- .../typescript/src/gipl-write-image-node.ts | 3 +- .../typescript/src/gipl-write-image.ts | 3 +- .../typescript/src/hdf5-read-image-node.ts | 3 +- .../typescript/src/hdf5-read-image.ts | 3 +- .../typescript/src/hdf5-write-image-node.ts | 3 +- .../typescript/src/hdf5-write-image.ts | 3 +- packages/image-io/typescript/src/itkConfig.js | 11 - .../typescript/src/jpeg-read-image-node.ts | 3 +- .../typescript/src/jpeg-read-image.ts | 3 +- .../typescript/src/jpeg-write-image-node.ts | 3 +- .../typescript/src/jpeg-write-image.ts | 3 +- .../typescript/src/lsm-read-image-node.ts | 3 +- .../image-io/typescript/src/lsm-read-image.ts | 3 +- .../typescript/src/lsm-write-image-node.ts | 3 +- .../typescript/src/lsm-write-image.ts | 3 +- .../typescript/src/meta-read-image-node.ts | 3 +- .../typescript/src/meta-read-image.ts | 3 +- .../typescript/src/meta-write-image-node.ts | 3 +- .../typescript/src/meta-write-image.ts | 3 +- .../typescript/src/mgh-read-image-node.ts | 3 +- .../image-io/typescript/src/mgh-read-image.ts | 3 +- .../typescript/src/mgh-write-image-node.ts | 3 +- .../typescript/src/mgh-write-image.ts | 3 +- .../typescript/src/minc-read-image-node.ts | 3 +- .../typescript/src/minc-read-image.ts | 3 +- .../typescript/src/minc-write-image-node.ts | 3 +- .../typescript/src/minc-write-image.ts | 3 +- .../typescript/src/mrc-read-image-node.ts | 3 +- .../image-io/typescript/src/mrc-read-image.ts | 3 +- .../typescript/src/mrc-write-image-node.ts | 3 +- .../typescript/src/mrc-write-image.ts | 3 +- .../typescript/src/nifti-read-image-node.ts | 3 +- .../typescript/src/nifti-read-image.ts | 3 +- .../typescript/src/nifti-write-image-node.ts | 3 +- .../typescript/src/nifti-write-image.ts | 3 +- .../typescript/src/nrrd-read-image-node.ts | 3 +- .../typescript/src/nrrd-read-image.ts | 3 +- .../typescript/src/nrrd-write-image-node.ts | 3 +- .../typescript/src/nrrd-write-image.ts | 3 +- packages/image-io/typescript/src/package.json | 1 + .../typescript/src/pipeline-worker-url.ts | 4 +- .../typescript/src/pipelines-base-url.ts | 2 +- .../typescript/src/png-read-image-node.ts | 3 +- .../image-io/typescript/src/png-read-image.ts | 3 +- .../typescript/src/png-write-image-node.ts | 3 +- .../typescript/src/png-write-image.ts | 3 +- .../typescript/src/scanco-read-image-node.ts | 3 +- .../typescript/src/scanco-read-image.ts | 3 +- .../typescript/src/scanco-write-image-node.ts | 3 +- .../typescript/src/scanco-write-image.ts | 3 +- .../typescript/src/tiff-read-image-node.ts | 3 +- .../typescript/src/tiff-read-image.ts | 3 +- .../typescript/src/tiff-write-image-node.ts | 3 +- .../typescript/src/tiff-write-image.ts | 3 +- .../typescript/src/vtk-read-image-node.ts | 3 +- .../image-io/typescript/src/vtk-read-image.ts | 3 +- .../typescript/src/vtk-write-image-node.ts | 3 +- .../typescript/src/vtk-write-image.ts | 3 +- .../typescript/src/wasm-read-image-node.ts | 3 +- .../typescript/src/wasm-read-image.ts | 3 +- .../typescript/src/wasm-write-image-node.ts | 3 +- .../typescript/src/wasm-write-image.ts | 3 +- .../src/wasm-zstd-read-image-node.ts | 3 +- .../typescript/src/wasm-zstd-read-image.ts | 3 +- .../src/wasm-zstd-write-image-node.ts | 3 +- .../typescript/src/wasm-zstd-write-image.ts | 3 +- .../demo-app/bio-rad-read-image-controller.ts | 171 ++++++++++ .../bio-rad-read-image-load-sample-inputs.ts | 28 ++ .../bio-rad-write-image-controller.ts | 175 ++++++++++ .../bio-rad-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/bmp-read-image-controller.ts | 172 ++++++++++ .../bmp-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/bmp-write-image-controller.ts | 175 ++++++++++ .../bmp-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/fdf-read-image-controller.ts | 172 ++++++++++ .../fdf-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/fdf-write-image-controller.ts | 176 ++++++++++ .../fdf-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/gdcm-read-image-controller.ts | 172 ++++++++++ .../gdcm-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/gdcm-write-image-controller.ts | 176 ++++++++++ .../gdcm-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/ge-adw-read-image-controller.ts | 172 ++++++++++ .../ge-adw-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/ge-adw-write-image-controller.ts | 176 ++++++++++ .../ge-adw-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/ge4-read-image-controller.ts | 172 ++++++++++ .../ge4-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/ge4-write-image-controller.ts | 176 ++++++++++ .../ge4-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/ge5-read-image-controller.ts | 172 ++++++++++ .../ge5-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/ge5-write-image-controller.ts | 176 ++++++++++ .../ge5-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/gipl-read-image-controller.ts | 172 ++++++++++ .../gipl-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/gipl-write-image-controller.ts | 176 ++++++++++ .../gipl-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/hdf5-read-image-controller.ts | 172 ++++++++++ .../hdf5-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/hdf5-write-image-controller.ts | 176 ++++++++++ .../hdf5-write-image-load-sample-inputs.ts | 28 ++ .../typescript/test/browser/demo-app/index.ts | 5 +- .../demo-app/jpeg-read-image-controller.ts | 172 ++++++++++ .../jpeg-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/jpeg-write-image-controller.ts | 176 ++++++++++ .../jpeg-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/lsm-read-image-controller.ts | 172 ++++++++++ .../lsm-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/lsm-write-image-controller.ts | 176 ++++++++++ .../lsm-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/meta-read-image-controller.ts | 172 ++++++++++ .../meta-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/meta-write-image-controller.ts | 176 ++++++++++ .../meta-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/mgh-read-image-controller.ts | 172 ++++++++++ .../mgh-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/mgh-write-image-controller.ts | 176 ++++++++++ .../mgh-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/minc-read-image-controller.ts | 172 ++++++++++ .../minc-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/minc-write-image-controller.ts | 176 ++++++++++ .../minc-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/mrc-read-image-controller.ts | 172 ++++++++++ .../mrc-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/mrc-write-image-controller.ts | 176 ++++++++++ .../mrc-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/nifti-read-image-controller.ts | 172 ++++++++++ .../nifti-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/nifti-write-image-controller.ts | 176 ++++++++++ .../nifti-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/nrrd-read-image-controller.ts | 172 ++++++++++ .../nrrd-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/nrrd-write-image-controller.ts | 176 ++++++++++ .../nrrd-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/png-read-image-controller.ts | 172 ++++++++++ .../png-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/png-write-image-controller.ts | 176 ++++++++++ .../png-write-image-load-sample-inputs.ts | 28 ++ .../browser/demo-app/read-image-controller.ts | 7 +- .../demo-app/scanco-read-image-controller.ts | 172 ++++++++++ .../scanco-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/scanco-write-image-controller.ts | 176 ++++++++++ .../scanco-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/tiff-read-image-controller.ts | 172 ++++++++++ .../tiff-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/tiff-write-image-controller.ts | 176 ++++++++++ .../tiff-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/vtk-read-image-controller.ts | 172 ++++++++++ .../vtk-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/vtk-write-image-controller.ts | 176 ++++++++++ .../vtk-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/wasm-read-image-controller.ts | 172 ++++++++++ .../wasm-read-image-load-sample-inputs.ts | 28 ++ .../demo-app/wasm-write-image-controller.ts | 176 ++++++++++ .../wasm-write-image-load-sample-inputs.ts | 28 ++ .../wasm-zstd-read-image-controller.ts | 172 ++++++++++ ...wasm-zstd-read-image-load-sample-inputs.ts | 28 ++ .../wasm-zstd-write-image-controller.ts | 176 ++++++++++ ...asm-zstd-write-image-load-sample-inputs.ts | 28 ++ .../demo-app/write-image-controller.ts | 5 +- .../write-image-load-sample-inputs.ts | 47 +-- .../typescript/test/node/bio-rad-test.js | 2 +- .../image-io/typescript/test/node/bmp-test.js | 2 +- .../image-io/typescript/test/node/fdf-test.js | 2 +- .../typescript/test/node/hdf5-test.js | 2 +- .../typescript/test/node/jpeg-test.js | 2 +- .../image-io/typescript/test/node/lsm-test.js | 2 +- .../typescript/test/node/meta-image-test.js | 2 +- .../image-io/typescript/test/node/mgh-test.js | 2 +- .../typescript/test/node/minc-test.js | 2 +- .../image-io/typescript/test/node/mrc-test.js | 2 +- .../typescript/test/node/nifti-test.js | 2 +- .../typescript/test/node/nrrd-test.js | 2 +- .../image-io/typescript/test/node/png-test.js | 2 +- .../test/node/read-image-node-test.js | 2 +- .../typescript/test/node/scanco-test.js | 2 +- .../typescript/test/node/tiff-test.js | 2 +- .../image-io/typescript/test/node/vtk-test.js | 2 +- .../typescript/test/node/wasm-test.js | 2 +- .../test/node/write-image-node-test.js | 2 +- packages/image-io/typescript/tsconfig.json | 7 +- .../emscripten/emscripten-pyodide-module.js | 2 +- .../demo/input-parameters-demo-typescript.js | 4 +- .../interface-functions-demo-typescript.js | 18 +- .../typescript/demo/io-packages-needed.js | 16 + .../typescript/demo/output-demo-typescript.js | 4 +- src/bindgen/typescript/function-module.js | 15 +- .../typescript/resources/demo-app/index.ts | 6 +- src/bindgen/typescript/resources/itkConfig.js | 11 - .../resources/pipeline-worker-url.ts | 4 +- .../resources/rollup.browser.config.js | 9 - .../resources/template.package.json | 33 +- .../typescript/resources/tsconfig.json | 8 +- .../typescript/resources/vite.config.js | 8 +- src/bindgen/typescript/results-module.js | 2 +- src/bindgen/typescript/typescript-bindgen.js | 17 - src/bindgen/typescript/typescript-bindings.js | 20 +- src/core/createWebWorkerPromise.ts | 2 +- .../internal/loadEmscriptenModuleWebWorker.ts | 3 +- 298 files changed, 10179 insertions(+), 785 deletions(-) delete mode 100644 packages/compare-images/typescript/src/itkConfig.js create mode 100644 packages/image-io/typescript/build/vite-rollup-watch.config.ts delete mode 100644 packages/image-io/typescript/src/itkConfig.js create mode 120000 packages/image-io/typescript/src/package.json create mode 100644 packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bmp-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bmp-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bmp-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/bmp-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/fdf-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/fdf-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/fdf-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/fdf-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge4-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge4-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge4-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge4-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge5-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge5-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge5-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/ge5-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gipl-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gipl-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gipl-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/gipl-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/lsm-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/lsm-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/lsm-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/lsm-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/meta-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/meta-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/meta-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/meta-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mgh-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mgh-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mgh-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mgh-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/minc-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/minc-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/minc-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/minc-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mrc-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mrc-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mrc-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/mrc-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nifti-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nifti-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nifti-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nifti-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/png-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/png-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/png-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/png-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/scanco-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/scanco-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/scanco-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/scanco-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/tiff-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/tiff-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/tiff-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/tiff-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/vtk-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/vtk-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/vtk-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/vtk-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-write-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-load-sample-inputs.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-controller.ts create mode 100644 packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-load-sample-inputs.ts create mode 100644 src/bindgen/typescript/demo/io-packages-needed.js delete mode 100644 src/bindgen/typescript/resources/itkConfig.js diff --git a/package.json b/package.json index ad0bfcec1..84135be75 100644 --- a/package.json +++ b/package.json @@ -38,18 +38,18 @@ "build:webpack": "webpack --mode production --progress --color && webpack --mode development --progress --color", "build:emscripten": "node ./src/build-emscripten.js", "build:emscripten:compress-stringify": "node ./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build build ", - "build:bindgen:typescript:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --package-version 0.6.1 --package-name @itk-wasm/compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b wasi-build bindgen --interface python --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 0.6.1 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python-web-demo:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --interface python-web-demo --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 0.6.1 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --package-version 1.0.0 --package-name @itk-wasm/compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b wasi-build bindgen --interface python --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 1.0.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python-web-demo:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --interface python-web-demo --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 1.0.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:dicom": "node ./src/itk-wasm-cli.js -s packages/dicom -b emscripten-build build", - "build:bindgen:typescript:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b emscripten-build bindgen --package-version 3.3.0 --package-name @itk-wasm/dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b wasi-build bindgen --package-version 3.3.0 --interface python --package-name itkwasm-dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b emscripten-build bindgen --package-version 4.0.0 --package-name @itk-wasm/dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b wasi-build bindgen --package-version 4.0.0 --interface python --package-name itkwasm-dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:compare-images": "node ./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build build", - "build:bindgen:typescript:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build bindgen --package-version 1.0.1 --package-name @itk-wasm/compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b wasi-build bindgen --package-version 1.0.1 --interface python --package-name itkwasm-compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build bindgen --package-version 3.0.1 --package-name @itk-wasm/compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b wasi-build bindgen --package-version 3.0.1 --interface python --package-name itkwasm-compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:image-io": "node ./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build build", - "build:bindgen:typescript:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build bindgen --package-version 0.1.0 --package-name @itk-wasm/image-io --package-description \"Input and output for scientific and medical image file formats.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b wasi-build bindgen --interface python --package-name itkwasm-image-io --package-description \"Input and output for scientific and medical image file formats.\" --package-version 0.1.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build bindgen --package-version 0.3.0 --package-name @itk-wasm/image-io --package-description \"Input and output for scientific and medical image file formats.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b wasi-build bindgen --interface python --package-name itkwasm-image-io --package-description \"Input and output for scientific and medical image file formats.\" --package-version 0.3.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:packages": "npm run build:emscripten:compress-stringify && npm run build:bindgen:typescript:compress-stringify && npm run build:emscripten:dicom && npm run build:bindgen:typescript:dicom && npm run build:emscripten:compare-images && npm run build:bindgen:typescript:compare-images && npm run build:emscripten:image-io && npm run build:bindgen:typescript:image-io", "build:wasi": "node ./src/build-wasi.js && npm run build:wasi:packages", "build:wasi:compress-stringify": "node ./src/itk-wasm-cli.js -i itkwasm/wasi:latest -s packages/compress-stringify -b wasi-build build", diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py index 5c4105cd3..055276878 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py @@ -1 +1 @@ -__version__ = "1.0.1" +__version__ = "3.0.1" diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py index a940ad6cd..ae6fb28b4 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py @@ -2,5 +2,5 @@ from ._version import __version__ -default_config = JsPackageConfig(f"https://cdn.jsdelivr.net/npm/@itk-wasm/compare-images@{__version__}/dist/bundles/compare-images.js") +default_config = JsPackageConfig(f"https://cdn.jsdelivr.net/npm/@itk-wasm/compare-images@{__version__}/dist/index.js") js_package = JsPackage(default_config) diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml b/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml index 227337467..792111b3c 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml @@ -31,7 +31,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", ] [tool.hatch.version] @@ -42,7 +42,7 @@ dependencies = [ "pytest", "pytest-pyodide", "itk-webassemblyinterface >= 1.0.b127", - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", ] [project.urls] diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py index 5c4105cd3..055276878 100644 --- a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py +++ b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py @@ -1 +1 @@ -__version__ = "1.0.1" +__version__ = "3.0.1" diff --git a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py index 5c4105cd3..055276878 100644 --- a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py +++ b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py @@ -1 +1 @@ -__version__ = "1.0.1" +__version__ = "3.0.1" diff --git a/packages/compare-images/typescript/README.md b/packages/compare-images/typescript/README.md index 47a452eef..514a01508 100644 --- a/packages/compare-images/typescript/README.md +++ b/packages/compare-images/typescript/README.md @@ -4,10 +4,6 @@ > Compare images with a tolerance for regression testing. -[👨‍💻 **Live API Demo** ✨](https://itk-wasm-compare-images-app.on.fleek.co/ ':include :type=iframe width=100% height=800px') - -[🕮 **Documentation** 📚](https://itk-wasm-compare-images-docs.on.fleek.co/) - ## Installation ```sh @@ -25,8 +21,6 @@ import { compareImages, setPipelinesBaseUrl, getPipelinesBaseUrl, - setPipelineWorkerUrl, - getPipelineWorkerUrl, } from "@itk-wasm/compare-images" ``` @@ -36,15 +30,16 @@ import { ```ts async function compareImages( - webWorker: null | Worker, + webWorker: null | Worker | boolean, testImage: Image, options: CompareImagesOptions = { baselineImages: [] as Image[], } ) : Promise ``` -| Parameter | Type | Description | -| :---------: | :-----: | :------------------- | -| `testImage` | *Image* | The input test image | +| Parameter | Type | Description | +| :---------: | :-------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `webWorker` | *null or Worker or boolean* | WebWorker to use for computation. Set to null to create a new worker. Or, pass an existing worker. Or, set to `false` to run in the current thread / worker. | +| `testImage` | *Image* | The input test image | **`CompareImagesOptions` interface:** @@ -58,12 +53,13 @@ async function compareImages( **`CompareImagesResult` interface:** -| Property | Type | Description | -| :----------------------: | :------: | :-------------------------------------------------------------------------------- | -| **webWorker** | *Worker* | WebWorker used for computation | -| `metrics` | *Object* | Metrics for the baseline with the fewest number of pixels outside the tolerances. | -| `differenceImage` | *Image* | Absolute difference image | -| `differenceUchar2dImage` | *Image* | Unsigned char, 2D difference image for rendering | +| Property | Type | Description | +| :----------------------: | :--------------: | :-------------------------------------------------------------------------------- | +| `webWorker` | *Worker* | WebWorker used for computation. | +| `metrics` | *JsonCompatible* | Metrics for the baseline with the fewest number of pixels outside the tolerances. | +| `differenceImage` | *Image* | Absolute difference image | +| `differenceUchar2dImage` | *Image* | Unsigned char, 2D difference image for rendering | + #### setPipelinesBaseUrl @@ -83,23 +79,6 @@ function setPipelinesBaseUrl( function getPipelinesBaseUrl() : string | URL ``` -#### setPipelineWorkerUrl - -*Set base URL for the itk-wasm pipeline worker script when vendored.* - -```ts -function setPipelineWorkerUrl( - baseUrl: string | URL -) : void -``` - -#### getPipelineWorkerUrl - -*Get base URL for the itk-wasm pipeline worker script when vendored.* - -```ts -function getPipelineWorkerUrl() : string | URL -``` ### Node interface @@ -108,10 +87,6 @@ Import: ```js import { compareImagesNode, - setPipelinesBaseUrl, - getPipelinesBaseUrl, - setPipelineWorkerUrl, - getPipelineWorkerUrl, } from "@itk-wasm/compare-images" ``` @@ -142,8 +117,10 @@ async function compareImagesNode( **`CompareImagesNodeResult` interface:** -| Property | Type | Description | -| :----------------------: | :------: | :-------------------------------------------------------------------------------- | -| `metrics` | *Object* | Metrics for the baseline with the fewest number of pixels outside the tolerances. | -| `differenceImage` | *Image* | Absolute difference image | -| `differenceUchar2dImage` | *Image* | Unsigned char, 2D difference image for rendering | +| Property | Type | Description | +| :----------------------: | :--------------: | :-------------------------------------------------------------------------------- | +| `metrics` | *JsonCompatible* | Metrics for the baseline with the fewest number of pixels outside the tolerances. | +| `differenceImage` | *Image* | Absolute difference image | +| `differenceUchar2dImage` | *Image* | Unsigned char, 2D difference image for rendering | + + diff --git a/packages/compare-images/typescript/build/rollup.browser.config.js b/packages/compare-images/typescript/build/rollup.browser.config.js index ac03845a3..98ec279b6 100644 --- a/packages/compare-images/typescript/build/rollup.browser.config.js +++ b/packages/compare-images/typescript/build/rollup.browser.config.js @@ -1,5 +1,4 @@ import { nodeResolve } from '@rollup/plugin-node-resolve' -import copy from 'rollup-plugin-copy' import typescript from '@rollup/plugin-typescript' import commonjs from '@rollup/plugin-commonjs' import nodePolyfills from 'rollup-plugin-polyfill-node' @@ -8,27 +7,32 @@ import terser from '@rollup/plugin-terser' import packageJson from '../package.json' assert { type: 'json' } import json from '@rollup/plugin-json' import path from 'path' +import OMT from "@surma/rollup-plugin-off-main-thread" + +const omtCustom = OMT() +omtCustom.resolveImportMeta = () => { + return 'import.meta.url' +} -const itkConfig = './src/itkConfig.js' const bundleName = path.basename(packageJson.name) export default { input: './src/index.ts', output: [ { - file: `./dist/bundles/${bundleName}.js`, + dir: `./dist`, format: 'es', sourcemap: true, // plugins: [terser(),], }, ], + onwarn: function onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + if (warning.message.includes('Very few browsers support ES modules in Workers.')) return; + console.log('onwarn', warning) + warn(warning); + }, plugins: [ - copy({ - targets: [ - { src: 'node_modules/itk-wasm/dist/web-workers/bundles/pipeline.worker.js', dest: 'dist/web-workers/' }, - ], - hook: 'writeBundle' - }), ignore(['crypto']), nodeResolve({ preferBuiltins: false, @@ -40,12 +44,6 @@ export default { nodePolyfills(), typescript(), json(), - ], - resolve: { - // where itk-wasm code has 'import ../itkConfig.js` point to the path of itkConfig - alias: { - '../itkConfig.js': itkConfig, - '../../itkConfig.js': itkConfig - } - } + omtCustom, + ] } diff --git a/packages/compare-images/typescript/build/rollup.node.config.js b/packages/compare-images/typescript/build/rollup.node.config.js index 431b29d3e..57d19955d 100644 --- a/packages/compare-images/typescript/build/rollup.node.config.js +++ b/packages/compare-images/typescript/build/rollup.node.config.js @@ -12,12 +12,16 @@ export default { input: './src/index-node.ts', output: [ { - file: `./dist/bundles/${bundleName}-node.js`, + dir: './dist', format: 'es', sourcemap: true, // plugins: [terser(),], }, ], + onwarn: function onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); + }, plugins: [ commonjs({ transformMixedEsModules: true diff --git a/packages/compare-images/typescript/build/vite.config.js b/packages/compare-images/typescript/build/vite.config.js index f40d37493..38df171ce 100644 --- a/packages/compare-images/typescript/build/vite.config.js +++ b/packages/compare-images/typescript/build/vite.config.js @@ -8,12 +8,18 @@ export default defineConfig({ outDir: '../../../demo-app', emptyOutDir: true, }, + worker: { + format: 'es' + }, + optimizeDeps: { + exclude: ['@itk-wasm/image-io'] + }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../dist/web-workers/*', dest: 'web-workers' }, + { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm.zst}', dest: 'pipelines' }, ], }) ], diff --git a/packages/compare-images/typescript/cypress.config.ts b/packages/compare-images/typescript/cypress.config.ts index 6ddaef889..c0d7712df 100644 --- a/packages/compare-images/typescript/cypress.config.ts +++ b/packages/compare-images/typescript/cypress.config.ts @@ -2,7 +2,7 @@ import { defineConfig } from "cypress"; export default defineConfig({ e2e: { - defaultCommandTimeout: 8000, + defaultCommandTimeout: 20000, setupNodeEvents(on, config) { // implement node event listeners here }, diff --git a/packages/compare-images/typescript/package.json b/packages/compare-images/typescript/package.json index 50e010445..4a4e34f9f 100644 --- a/packages/compare-images/typescript/package.json +++ b/packages/compare-images/typescript/package.json @@ -1,16 +1,16 @@ { "name": "@itk-wasm/compare-images", - "version": "1.0.1", + "version": "3.0.1", "description": "Compare images with a tolerance for regression testing.", "type": "module", - "module": "./dist/bundles/compare-images.js", + "module": "./dist/index.js", "types": "./dist/src/index.d.ts", "exports": { ".": { "types": "./dist/src/index.d.ts", - "browser": "./dist/bundles/compare-images.js", - "node": "./dist/bundles/compare-images-node.js", - "default": "./dist/bundles/compare-images.js" + "browser": "./dist/index.js", + "node": "./dist/index-node.js", + "default": "./dist/index.js" } }, "scripts": { @@ -40,30 +40,30 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.138" + "itk-wasm": "^1.0.0-b.149" }, "devDependencies": { + "@itk-wasm/image-io": "^0.3.0", "@rollup/plugin-commonjs": "^24.0.0", "@rollup/plugin-json": "^6.0.0", "@rollup/plugin-node-resolve": "^15.1.0", "@rollup/plugin-terser": "^0.4.0", "@rollup/plugin-typescript": "^11.1.1", "@shoelace-style/shoelace": "^2.5.2", + "@surma/rollup-plugin-off-main-thread": "^2.2.3", "@types/node": "^20.2.5", "ava": "^5.3.1", "cypress": "^12.17.2", "debug": "^4.3.4", - "itk-image-io": "^1.0.0-b.130", "rollup": "^3.9.0", - "rollup-plugin-copy": "^3.4.0", "rollup-plugin-ignore": "^1.0.10", "rollup-plugin-polyfill-node": "^0.12.0", "shx": "^0.3.4", "supports-color": "^9.3.1", "tslib": "^2.5.2", "typescript": "^5.0.4", - "vite": "^4.3.3", - "vite-plugin-static-copy": "^0.14.0" + "vite": "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" }, "repository": { "type": "git", diff --git a/packages/compare-images/typescript/src/compare-double-images-node.ts b/packages/compare-images/typescript/src/compare-double-images-node.ts index a65920bca..b7d1661f3 100644 --- a/packages/compare-images/typescript/src/compare-double-images-node.ts +++ b/packages/compare-images/typescript/src/compare-double-images-node.ts @@ -81,7 +81,7 @@ async function compareDoubleImagesNode( options.ignoreBoundaryPixels && args.push('--ignore-boundary-pixels') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'compare-double-images') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'compare-double-images') const { returnValue, diff --git a/packages/compare-images/typescript/src/compare-double-images.ts b/packages/compare-images/typescript/src/compare-double-images.ts index 9c836baf0..b2bbb72f3 100644 --- a/packages/compare-images/typescript/src/compare-double-images.ts +++ b/packages/compare-images/typescript/src/compare-double-images.ts @@ -10,9 +10,7 @@ import CompareDoubleImagesOptions from './compare-double-images-options.js' import CompareDoubleImagesResult from './compare-double-images-result.js' import CompareImagesMetric from './compare-images-metric.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' -import { getPipelineWorkerUrl } from './pipeline-worker-url.js' /** * Compare double pixel type images with a tolerance for regression testing. @@ -91,7 +89,7 @@ async function compareDoubleImages( returnValue, stderr, outputs - } = await runPipeline(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl(), pipelineWorkerUrl: getPipelineWorkerUrl() }) + } = await runPipeline(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl(), }) if (returnValue !== 0) { throw new Error(stderr) } diff --git a/packages/compare-images/typescript/src/index.ts b/packages/compare-images/typescript/src/index.ts index d02f4ed6a..548bf9827 100644 --- a/packages/compare-images/typescript/src/index.ts +++ b/packages/compare-images/typescript/src/index.ts @@ -1,5 +1,4 @@ export * from './pipelines-base-url.js' -export * from './pipeline-worker-url.js' import CompareImagesMetric from './compare-images-metric.js' export type { CompareImagesMetric } diff --git a/packages/compare-images/typescript/src/itkConfig.js b/packages/compare-images/typescript/src/itkConfig.js deleted file mode 100644 index be9beaf3f..000000000 --- a/packages/compare-images/typescript/src/itkConfig.js +++ /dev/null @@ -1,11 +0,0 @@ -import version from 'itk-wasm' - -const itkConfig = { - // Use the worker bundled by vite or webpack - pipelineWorkerUrl: null, - imageIOUrl: `https://cdn.jsdelivr.net/npm/itk-image-io@${version}`, - meshIOUrl: `https://cdn.jsdelivr.net/npm/itk-mesh-io@${version}`, - pipelinesUrl: '/pipelines' -} - -export default itkConfig diff --git a/packages/compare-images/typescript/src/vector-magnitude-node.ts b/packages/compare-images/typescript/src/vector-magnitude-node.ts index 7b30e5651..fe26ccb09 100644 --- a/packages/compare-images/typescript/src/vector-magnitude-node.ts +++ b/packages/compare-images/typescript/src/vector-magnitude-node.ts @@ -10,7 +10,6 @@ import { import VectorMagnitudeNodeResult from './vector-magnitude-node-result.js' - import path from 'path' /** @@ -45,7 +44,7 @@ async function vectorMagnitudeNode( // Options args.push('--memory-io') - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'vector-magnitude') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'vector-magnitude') const { returnValue, diff --git a/packages/compare-images/typescript/src/vector-magnitude.ts b/packages/compare-images/typescript/src/vector-magnitude.ts index 4a5bc9ca5..4a6785b98 100644 --- a/packages/compare-images/typescript/src/vector-magnitude.ts +++ b/packages/compare-images/typescript/src/vector-magnitude.ts @@ -10,7 +10,6 @@ import { import VectorMagnitudeResult from './vector-magnitude-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -22,7 +21,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function vectorMagnitude( - webWorker: null | Worker, + webWorker: null | Worker | boolean, vectorImage: Image ) : Promise { diff --git a/packages/compare-images/typescript/test/browser/demo-app/compare-double-images-controller.ts b/packages/compare-images/typescript/test/browser/demo-app/compare-double-images-controller.ts index 1cb976bc4..13a479364 100644 --- a/packages/compare-images/typescript/test/browser/demo-app/compare-double-images-controller.ts +++ b/packages/compare-images/typescript/test/browser/demo-app/compare-double-images-controller.ts @@ -1,9 +1,9 @@ // Generated file. To retain edits, remove this comment. -import { readImageFile } from 'itk-wasm' -import { writeImageArrayBuffer } from 'itk-wasm' +import { readImage } from '@itk-wasm/image-io' +import { writeImage } from '@itk-wasm/image-io' import { copyImage } from 'itk-wasm' -import * as compareImages from '../../../dist/bundles/compare-images.js' +import * as compareImages from '../../../dist/index.js' import compareDoubleImagesLoadSampleInputs, { usePreRun } from "./compare-double-images-load-sample-inputs.js" class CompareDoubleImagesModel { @@ -46,7 +46,7 @@ class CompareDoubleImagesController { const dataTransfer = event.dataTransfer const files = event.target.files || dataTransfer.files - const { image, webWorker } = await readImageFile(null, files[0]) + const { image, webWorker } = await readImage(null, files[0]) webWorker.terminate() model.inputs.set("testImage", image) const details = document.getElementById("compareDoubleImages-test-image-details") @@ -61,7 +61,7 @@ class CompareDoubleImagesController { const dataTransfer = event.dataTransfer const files = event.target.files || dataTransfer.files - const readImages = await Promise.all(Array.from(files).map(async (file) => readImageFile(null, file))) + const readImages = await Promise.all(Array.from(files).map(async (file) => readImage(null, file))) readImages.forEach(img => img.webWorker.terminate()) const inputImages = readImages.map(img => img.image) model.options.set("baselineImages", inputImages) @@ -110,10 +110,10 @@ class CompareDoubleImagesController { const differenceImageDownloadFormat = document.getElementById('difference-image-output-format') const downloadFormat = differenceImageDownloadFormat.value || 'nrrd' const fileName = `differenceImage.${downloadFormat}` - const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("differenceImage")), fileName) + const { webWorker, serializedImage } = await writeImage(null, copyImage(model.outputs.get("differenceImage")), fileName) webWorker.terminate() - globalThis.downloadFile(arrayBuffer, fileName) + globalThis.downloadFile(serializedImage, fileName) } }) @@ -125,10 +125,10 @@ class CompareDoubleImagesController { const differenceUchar2dImageDownloadFormat = document.getElementById('difference-uchar-2d-image-output-format') const downloadFormat = differenceUchar2dImageDownloadFormat.value || 'nrrd' const fileName = `differenceUchar2dImage.${downloadFormat}` - const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("differenceUchar2dImage")), fileName) + const { webWorker, serializedImage } = await writeImage(null, copyImage(model.outputs.get("differenceUchar2dImage")), fileName) webWorker.terminate() - globalThis.downloadFile(arrayBuffer, fileName) + globalThis.downloadFile(serializedImage, fileName) } }) diff --git a/packages/compare-images/typescript/test/browser/demo-app/compare-images-controller.ts b/packages/compare-images/typescript/test/browser/demo-app/compare-images-controller.ts index 606715b7e..8eb971b91 100644 --- a/packages/compare-images/typescript/test/browser/demo-app/compare-images-controller.ts +++ b/packages/compare-images/typescript/test/browser/demo-app/compare-images-controller.ts @@ -1,8 +1,6 @@ -// Generated file. To retain edits, remove this comment. - -import { readImageFile } from 'itk-wasm' -import { writeImageArrayBuffer, copyImage } from 'itk-wasm' -import * as compareImages from '../../../dist/bundles/compare-images.js' +import { readImage } from '@itk-wasm/image-io' +import { writeImage } from '@itk-wasm/image-io' +import * as compareImages from '../../../dist/index.js' import compareImagesLoadSampleInputs from "./compare-images-load-sample-inputs.js" class CompareImagesModel { @@ -46,7 +44,7 @@ class CompareImagesController { const dataTransfer = event.dataTransfer const files = event.target.files || dataTransfer.files - const { image, webWorker } = await readImageFile(null, files[0]) + const { image, webWorker } = await readImage(null, files[0]) webWorker.terminate() model.inputs.set("testImage", image) const details = document.getElementById("compareImages-test-image-details") @@ -61,7 +59,7 @@ class CompareImagesController { const dataTransfer = event.dataTransfer const files = event.target.files || dataTransfer.files - const readImages = await Promise.all(Array.from(files).map(async (file) => readImageFile(null, file))) + const readImages = await Promise.all(Array.from(files).map(async (file) => readImage(null, file))) readImages.forEach(img => img.webWorker.terminate()) const inputImages = readImages.map(img => img.image) model.options.set("baselineImages", inputImages) @@ -110,10 +108,10 @@ class CompareImagesController { const differenceImageDownloadFormat = document.getElementById('difference-image-output-format') const downloadFormat = differenceImageDownloadFormat.value || 'nrrd' const fileName = `differenceImage.${downloadFormat}` - const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("differenceImage")), fileName) + const { webWorker, serializedImage } = await writeImage(null, copyImage(model.outputs.get("differenceImage")), fileName) webWorker.terminate() - globalThis.downloadFile(arrayBuffer, fileName) + globalThis.downloadFile(serializedImage, fileName) } }) diff --git a/packages/compare-images/typescript/test/browser/demo-app/index.ts b/packages/compare-images/typescript/test/browser/demo-app/index.ts index 8874281cc..fce6a1f03 100644 --- a/packages/compare-images/typescript/test/browser/demo-app/index.ts +++ b/packages/compare-images/typescript/test/browser/demo-app/index.ts @@ -1,9 +1,7 @@ -import * as compareImages from '../../../dist/bundles/compare-images.js' +import * as compareImages from '../../../dist/index.js' // Use local, vendored WebAssembly module assets const pipelinesBaseUrl: string | URL = new URL('/pipelines', document.location.origin).href compareImages.setPipelinesBaseUrl(pipelinesBaseUrl) -const pipelineWorkerUrl: string | URL | null = new URL('/web-workers/pipeline.worker.js', document.location.origin).href -compareImages.setPipelineWorkerUrl(pipelineWorkerUrl) import './compare-images-controller.js' diff --git a/packages/compare-images/typescript/test/browser/demo-app/vector-magnitude-controller.ts b/packages/compare-images/typescript/test/browser/demo-app/vector-magnitude-controller.ts index 71ca09ffa..7e2f4d114 100644 --- a/packages/compare-images/typescript/test/browser/demo-app/vector-magnitude-controller.ts +++ b/packages/compare-images/typescript/test/browser/demo-app/vector-magnitude-controller.ts @@ -1,9 +1,9 @@ // Generated file. To retain edits, remove this comment. -import { readImageFile } from 'itk-wasm' -import { writeImageArrayBuffer } from 'itk-wasm' +import { readImage } from '@itk-wasm/image-io' +import { writeImage } from '@itk-wasm/image-io' import { copyImage } from 'itk-wasm' -import * as compareImages from '../../../dist/bundles/compare-images.js' +import * as compareImages from '../../../dist/index.js' import vectorMagnitudeLoadSampleInputs, { usePreRun } from "./vector-magnitude-load-sample-inputs.js" class VectorMagnitudeModel { @@ -46,7 +46,7 @@ class VectorMagnitudeController { const dataTransfer = event.dataTransfer const files = event.target.files || dataTransfer.files - const { image, webWorker } = await readImageFile(null, files[0]) + const { image, webWorker } = await readImage(null, files[0]) webWorker.terminate() model.inputs.set("vectorImage", image) const details = document.getElementById("vectorMagnitude-vector-image-details") @@ -66,10 +66,10 @@ class VectorMagnitudeController { const magnitudeImageDownloadFormat = document.getElementById('magnitude-image-output-format') const downloadFormat = magnitudeImageDownloadFormat.value || 'nrrd' const fileName = `magnitudeImage.${downloadFormat}` - const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("magnitudeImage")), fileName) + const { webWorker, serializedImage } = await writeImage(null, copyImage(model.outputs.get("magnitudeImage")), fileName) webWorker.terminate() - globalThis.downloadFile(arrayBuffer, fileName) + globalThis.downloadFile(serializedImage, fileName) } }) diff --git a/packages/compare-images/typescript/test/node/compare-double-images-test.js b/packages/compare-images/typescript/test/node/compare-double-images-test.js index fc0a3b374..31f43eb50 100644 --- a/packages/compare-images/typescript/test/node/compare-double-images-test.js +++ b/packages/compare-images/typescript/test/node/compare-double-images-test.js @@ -1,19 +1,19 @@ import test from 'ava' import path from 'path' -import { compareDoubleImagesNode } from '../../dist/bundles/compare-images-node.js' -import { readImageLocalFile } from 'itk-wasm' +import { compareDoubleImagesNode } from '../../dist/index-node.js' +import { readImageNode } from '@itk-wasm/image-io' -const inputPathPrefix = '../test/data/input/'; +const inputPathPrefix = '../test/data/input/' test('compareDoubleImagesNode produces the expected metrics and difference images', async t => { const testImageFile = 'cake_easy.iwi.cbor' const testImagePath = path.join(inputPathPrefix, testImageFile) - const testImage = await readImageLocalFile(testImagePath) + const testImage = await readImageNode(testImagePath) const baselineImageFile = 'cake_hard.iwi.cbor' const baselineImagePath = path.join(inputPathPrefix, baselineImageFile) - const baselineImage = await readImageLocalFile(baselineImagePath) + const baselineImage = await readImageNode(baselineImagePath) const { metrics, differenceImage, differenceUchar2dImage } = await compareDoubleImagesNode(testImage, { baselineImages: [baselineImage,] }) diff --git a/packages/compare-images/typescript/test/node/compare-images-test.js b/packages/compare-images/typescript/test/node/compare-images-test.js index f3e32f556..cfa72189f 100644 --- a/packages/compare-images/typescript/test/node/compare-images-test.js +++ b/packages/compare-images/typescript/test/node/compare-images-test.js @@ -1,19 +1,19 @@ import test from 'ava' import path from 'path' -import { compareImagesNode } from '../../dist/bundles/compare-images-node.js' -import { readImageLocalFile } from 'itk-wasm' +import { compareImagesNode } from '../../dist/index-node.js' +import { readImageNode } from '@itk-wasm/image-io' const inputPathPrefix = '../test/data/input/' test('compareImagesNode produces the expected metrics and difference images for uint8 inputs', async t => { const testImageFile = 'cake_easy.png' const testImagePath = path.join(inputPathPrefix, testImageFile) - const testImage = await readImageLocalFile(testImagePath) + const testImage = await readImageNode(testImagePath) const baselineImageFile = 'cake_hard.png' const baselineImagePath = path.join(inputPathPrefix, baselineImageFile) - const baselineImage = await readImageLocalFile(baselineImagePath) + const baselineImage = await readImageNode(baselineImagePath) const { metrics, differenceImage, differenceUchar2dImage } = await compareImagesNode(testImage, { baselineImages: [baselineImage,] }) @@ -31,11 +31,11 @@ test('compareImagesNode produces the expected metrics and difference images for test('compareImagesNode produces the expected metrics and difference images for rgb inputs', async t => { const testImageFile = 'apple.jpg' const testImagePath = path.join(inputPathPrefix, testImageFile) - const testImage = await readImageLocalFile(testImagePath) + const testImage = await readImageNode(testImagePath) const baselineImageFile = 'orange.jpg' const baselineImagePath = path.join(inputPathPrefix, baselineImageFile) - const baselineImage = await readImageLocalFile(baselineImagePath) + const baselineImage = await readImageNode(baselineImagePath) const { metrics, differenceImage, differenceUchar2dImage } = await compareImagesNode(testImage, { baselineImages: [baselineImage,] }) diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py index 43c4ab005..5becc17c0 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py @@ -1 +1 @@ -__version__ = "0.6.1" +__version__ = "1.0.0" diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py b/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py index 43c4ab005..5becc17c0 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py @@ -1 +1 @@ -__version__ = "0.6.1" +__version__ = "1.0.0" diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/wasm_modules/compress-stringify.wasi.wasm b/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/wasm_modules/compress-stringify.wasi.wasm index 5ff4a98762123ded851135b9013e3e8ab223f273..3ec808a50995b31bde0a6414ac18464772919860 100755 GIT binary patch delta 288743 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%0AJHb`o2zt7%4l`$s=yrNgsgiMY(NJ;)jr8P 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%0AkP3o#t@QqhS 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 |MMn( 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 diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/wasm_modules/parse-string-decompress.wasi.wasm b/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/wasm_modules/parse-string-decompress.wasi.wasm index 499b4310bf2e896d46de2b9101b97400d1cd8c0d..cda93bd0fd97efce99a300c93bf00b7d9aced924 100755 GIT binary patch delta 147956 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 delta 80245 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%0A#}EuEdd>QUz3OXv;Gfh# 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 G=lwU$cQuIs diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py b/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py index 43c4ab005..5becc17c0 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py @@ -1 +1 @@ -__version__ = "0.6.1" +__version__ = "1.0.0" diff --git a/packages/compress-stringify/typescript/build/vite.config.js b/packages/compress-stringify/typescript/build/vite.config.js index f40d37493..222e14626 100644 --- a/packages/compress-stringify/typescript/build/vite.config.js +++ b/packages/compress-stringify/typescript/build/vite.config.js @@ -13,7 +13,6 @@ export default defineConfig({ viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../dist/web-workers/*', dest: 'web-workers' }, ], }) ], diff --git a/packages/compress-stringify/typescript/cypress.config.ts b/packages/compress-stringify/typescript/cypress.config.ts index 17161e32e..c0d7712df 100644 --- a/packages/compress-stringify/typescript/cypress.config.ts +++ b/packages/compress-stringify/typescript/cypress.config.ts @@ -2,6 +2,7 @@ import { defineConfig } from "cypress"; export default defineConfig({ e2e: { + defaultCommandTimeout: 20000, setupNodeEvents(on, config) { // implement node event listeners here }, diff --git a/packages/compress-stringify/typescript/package-lock.json b/packages/compress-stringify/typescript/package-lock.json index f6de23043..59378b498 100644 --- a/packages/compress-stringify/typescript/package-lock.json +++ b/packages/compress-stringify/typescript/package-lock.json @@ -1,15 +1,15 @@ { "name": "@itk-wasm/compress-stringify", - "version": "0.6.1", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@itk-wasm/compress-stringify", - "version": "0.6.1", + "version": "1.0.0", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.142" + "itk-wasm": "^1.0.0-b.149" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.0.0", @@ -20,7 +20,7 @@ "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", "ava": "^5.1.0", - "cypress": "^13.2.0", + "cypress": "^13.3.1", "rollup": "^3.9.0", "rollup-plugin-copy": "^3.4.0", "rollup-plugin-ignore": "^1.0.10", @@ -30,14 +30,14 @@ "supports-color": "^9.3.1", "tslib": "^2.5.2", "typescript": "^5.0.4", - "vite": "^4.3.3", - "vite-plugin-static-copy": "^0.14.0" + "vite": "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" } }, "node_modules/@babel/runtime": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.22.15.tgz", - "integrity": "sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz", + "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==", "dependencies": { "regenerator-runtime": "^0.14.0" }, @@ -56,12 +56,12 @@ } }, "node_modules/@ctrl/tinycolor": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz", - "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-4.0.2.tgz", + "integrity": "sha512-fKQinXE9pJ83J1n+C3rDl2xNLJwfoYNvXLRy5cYZA9hBJJw2q+sbb/AOSNKmLxnTWyNTmy4994dueSwP4opi5g==", "dev": true, "engines": { - "node": ">=10" + "node": ">=14" } }, "node_modules/@cypress/request": { @@ -465,28 +465,28 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.4.1.tgz", - "integrity": "sha512-jk3WqquEJRlcyu7997NtR5PibI+y5bi+LS3hPmguVClypenMsCY3CBa3LAQnozRCtCrYWSEtAdiskpamuJRFOQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.5.0.tgz", + "integrity": "sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==", "dev": true, "dependencies": { - "@floating-ui/utils": "^0.1.1" + "@floating-ui/utils": "^0.1.3" } }, "node_modules/@floating-ui/dom": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.2.tgz", - "integrity": "sha512-6ArmenS6qJEWmwzczWyhvrXRdI/rI78poBcW0h/456+onlabit+2G+QxHx5xTOX60NBJQXjsCLFbW2CmsXpUog==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.5.3.tgz", + "integrity": "sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==", "dev": true, "dependencies": { - "@floating-ui/core": "^1.4.1", - "@floating-ui/utils": "^0.1.1" + "@floating-ui/core": "^1.4.2", + "@floating-ui/utils": "^0.1.3" } }, "node_modules/@floating-ui/utils": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.2.tgz", - "integrity": "sha512-ou3elfqG/hZsbmF4bxeJhPHIf3G2pm0ujc39hYEZrfVqt7Vk/Zji6CXc3W0pmYM8BW1g40U+akTl9DKZhFhInQ==", + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.1.6.tgz", + "integrity": "sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==", "dev": true }, "node_modules/@hapi/hoek": { @@ -563,20 +563,29 @@ } }, "node_modules/@lit-labs/react": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.0.2.tgz", - "integrity": "sha512-bRr0uVaLzVMv/r6bNui91rwsY3UuOYDef5wCvfABQ3ipVtArz8TbH2k4Cn8UgLG/9IXO7IhAYt5xwMHaljxCAg==", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@lit-labs/react/-/react-2.1.1.tgz", + "integrity": "sha512-wr15ZOCZ7t2yB8UEfQ6oSRCmfxpIjhzDkN8DlgSOwsbJzWQTk8hxHRLy7Rra6mxrIajqvrMWQB2VskUU2uuoRA==", "dev": true, - "peerDependencies": { - "@types/react": "17 || 18" + "dependencies": { + "@lit/react": "1.0.0" } }, "node_modules/@lit-labs/ssr-dom-shim": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.1.tgz", - "integrity": "sha512-kXOeFbfCm4fFf2A3WwVEeQj55tMZa8c8/f9AKHMobQMkzNUfUj+antR3fRPaZJawsa1aZiP/Da3ndpZrwEe4rQ==", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.1.2.tgz", + "integrity": "sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==", "dev": true }, + "node_modules/@lit/react": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@lit/react/-/react-1.0.0.tgz", + "integrity": "sha512-uTuU6vpxtZvCWxcu3GNosckP2JpFWZpMKjhwQ42Bzu/OU9kjStJspA04o7RadecQfx0YiFIImX3qek15BXhaWQ==", + "dev": true, + "peerDependencies": { + "@types/react": "17 || 18" + } + }, "node_modules/@lit/reactive-element": { "version": "1.6.3", "resolved": "https://registry.npmjs.org/@lit/reactive-element/-/reactive-element-1.6.3.tgz", @@ -647,9 +656,9 @@ } }, "node_modules/@rollup/plugin-inject": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.3.tgz", - "integrity": "sha512-411QlbL+z2yXpRWFXSmw/teQRMkXcAAC8aYTemc15gwJRpvEVDQwoe+N/HTFD8RFG8+88Bme9DK2V9CVm7hJdA==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-inject/-/plugin-inject-5.0.4.tgz", + "integrity": "sha512-dM93Nyqp9Ah14jvThFFA30ifjB8cDKk3Bx69M1nIIHGytXug3VrTv5HEuYBzevu45HvZ0ho7t+40bmScmkzZhg==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -660,7 +669,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -669,9 +678,9 @@ } }, "node_modules/@rollup/plugin-json": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.0.tgz", - "integrity": "sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-json/-/plugin-json-6.0.1.tgz", + "integrity": "sha512-RgVfl5hWMkxN1h/uZj8FVESvPuBJ/uf6ly6GTj0GONnkfoBN5KC0MSz+PN2OLDgYXMhtG0mWpTrkiOjoxAIevw==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1" @@ -680,7 +689,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -689,9 +698,9 @@ } }, "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.1", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.1.tgz", - "integrity": "sha512-nsbUg588+GDSu8/NS8T4UAshO6xeaOfINNuXeVHcKV02LJtoRaM1SiOacClw4kws1SFiNhdLGxlbMY9ga/zs/w==", + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -705,7 +714,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.78.0||^3.0.0" + "rollup": "^2.78.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -714,9 +723,9 @@ } }, "node_modules/@rollup/plugin-terser": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.3.tgz", - "integrity": "sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==", + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", + "integrity": "sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==", "dev": true, "dependencies": { "serialize-javascript": "^6.0.1", @@ -727,7 +736,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.x || ^3.x" + "rollup": "^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -736,9 +745,9 @@ } }, "node_modules/@rollup/plugin-typescript": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.3.tgz", - "integrity": "sha512-8o6cNgN44kQBcpsUJTbTXMTtb87oR1O0zgP3Dxm71hrNgparap3VujgofEilTYJo+ivf2ke6uy3/E5QEaiRlDA==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-typescript/-/plugin-typescript-11.1.5.tgz", + "integrity": "sha512-rnMHrGBB0IUEv69Q8/JGRD/n4/n6b3nfpufUu26axhUcboUzv/twfZU8fIBbTOphRAe0v8EyxzeDpKXqGHfyDA==", "dev": true, "dependencies": { "@rollup/pluginutils": "^5.0.1", @@ -748,7 +757,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^2.14.0||^3.0.0", + "rollup": "^2.14.0||^3.0.0||^4.0.0", "tslib": "*", "typescript": ">=3.7.0" }, @@ -762,9 +771,9 @@ } }, "node_modules/@rollup/pluginutils": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", - "integrity": "sha512-0KJnIoRI8A+a1dqOYLxH8vBf8bphDmty5QvIm2hqm7oFCFYKCAZWWd2hXgMibaPsNDhI0AtpYfQZJG47pt/k4g==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.5.tgz", + "integrity": "sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==", "dev": true, "dependencies": { "@types/estree": "^1.0.0", @@ -775,7 +784,7 @@ "node": ">=14.0.0" }, "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" }, "peerDependenciesMeta": { "rollup": { @@ -794,20 +803,20 @@ } }, "node_modules/@shoelace-style/localize": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@shoelace-style/localize/-/localize-3.1.1.tgz", - "integrity": "sha512-NkM/hj3Js6yXCU9WxhsyxRUdyqUUUl/BSvIluUMptQteUWGOJaoyP1iMbOMqO544DYMzBfnoCw66ZHkGuTdKgA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@shoelace-style/localize/-/localize-3.1.2.tgz", + "integrity": "sha512-Hf45HeO+vdQblabpyZOTxJ4ZeZsmIUYXXPmoYrrR4OJ5OKxL+bhMz5mK8JXgl7HsoEowfz7+e248UGi861de9Q==", "dev": true }, "node_modules/@shoelace-style/shoelace": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/@shoelace-style/shoelace/-/shoelace-2.8.0.tgz", - "integrity": "sha512-WigVUaW+MptefOW4zUlZaq+zn0n2hP+I4/mztoeJii5u3ex1CGexfQGcdw2gx6d7P7LAa6/NW0TlgAELzJQnCA==", + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/@shoelace-style/shoelace/-/shoelace-2.9.0.tgz", + "integrity": "sha512-nxvDDYlTuACLLBuuR8TmTKiU0mrhzzwnbXbA4lpvaF+Ee5bS/VgKzr0nWrMXT3scpUEu/LPtqfoZcqWqaU/7DQ==", "dev": true, "dependencies": { - "@ctrl/tinycolor": "^3.5.0", + "@ctrl/tinycolor": "^4.0.1", "@floating-ui/dom": "^1.2.1", - "@lit-labs/react": "^2.0.1", + "@lit-labs/react": "^2.0.3", "@shoelace-style/animations": "^1.1.0", "@shoelace-style/localize": "^3.1.1", "composed-offset-position": "^0.0.4", @@ -849,20 +858,20 @@ "integrity": "sha512-Bv50pouFqlmIZDcAA2Nrpk9tjJpAPlqHHeD5h0noK+oNXMimrZ/hMbJK2N09Svr6TI/S6nT63dzkWoim4ZzTuw==" }, "node_modules/@types/emscripten": { - "version": "1.39.7", - "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.7.tgz", - "integrity": "sha512-tLqYV94vuqDrXh515F/FOGtBcRMTPGvVV1LzLbtYDcQmmhtpf/gLYf+hikBbQk8MzOHNz37wpFfJbYAuSn8HqA==" + "version": "1.39.8", + "resolved": "https://registry.npmjs.org/@types/emscripten/-/emscripten-1.39.8.tgz", + "integrity": "sha512-Rk0HKcMXFUuqT32k1kXHZWgxiMvsyYsmlnjp0rLKa0MMoqXLE3T9dogDBTRfuc3SAsXu97KD3k4SKR1lHqd57w==" }, "node_modules/@types/estree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.1.tgz", - "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.2.tgz", + "integrity": "sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==", "dev": true }, "node_modules/@types/fs-extra": { - "version": "8.1.2", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.2.tgz", - "integrity": "sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==", + "version": "8.1.3", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.3.tgz", + "integrity": "sha512-7IdV01N0u/CaVO0fuY1YmEg14HQN3+EW8mpNgg6NEfxEl/lzCa5OxlBu3iFsCAdamnYOcTQ7oEi43Xc/67Rgzw==", "dev": true, "dependencies": { "@types/node": "*" @@ -885,22 +894,25 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.6.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.6.0.tgz", - "integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==", - "dev": true + "version": "20.8.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz", + "integrity": "sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "version": "15.7.8", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.8.tgz", + "integrity": "sha512-kMpQpfZKSCBqltAJwskgePRaYRFukDkm1oItcAbC3gNELR20XIBcN9VRgg4+m8DKsTfkWeA4m4Imp4DDuWy7FQ==", "dev": true, "peer": true }, "node_modules/@types/react": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", - "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "version": "18.2.28", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.28.tgz", + "integrity": "sha512-ad4aa/RaaJS3hyGz0BGegdnSRXQBkd1CCYDCdNjBPg90UUpLgo+WlJqb9fMYUxtehmzF3PJaTWqRZjko6BRzBg==", "dev": true, "peer": true, "dependencies": { @@ -916,9 +928,9 @@ "dev": true }, "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==", + "version": "0.16.4", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.4.tgz", + "integrity": "sha512-2L9ifAGl7wmXwP4v3pN4p2FLhD0O1qsJpvKmNin5VA8+UvNVb447UDaAEV6UdrkA+m/Xs58U1RFps44x6TFsVQ==", "dev": true, "peer": true }, @@ -929,21 +941,21 @@ "dev": true }, "node_modules/@types/sizzle": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", - "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.4.tgz", + "integrity": "sha512-jA2llq2zNkg8HrALI7DtWzhALcVH0l7i89yhY3iBdOz6cBPeACoFq+fkQrjHA39t1hnSFOboZ7A/AY5MMZSlag==", "dev": true }, "node_modules/@types/trusted-types": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.3.tgz", - "integrity": "sha512-NfQ4gyz38SL8sDNrSixxU2Os1a5xcdFxipAFxYEuLUlvU2uDwS4NUpsImcf1//SlWItCVMMLiylsxbmNMToV/g==", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", + "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==", "dev": true }, "node_modules/@types/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.1.tgz", + "integrity": "sha512-CHzgNU3qYBnp/O4S3yv2tXPlvMTq0YWSTVg2/JYLqWZGHwwgJGAwd00poay/11asPq8wLFwHzubyInqHIFmmiw==", "dev": true, "optional": true, "dependencies": { @@ -1250,9 +1262,9 @@ "dev": true }, "node_modules/axios": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.0.tgz", - "integrity": "sha512-D4DdjDo5CY50Qms0qGQTTw6Q44jl7zRwY7bthds06pUGfChBCTcQs+N743eFWGEd6pRTMd6A+I87aWyFV5wiZQ==", + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.5.1.tgz", + "integrity": "sha512-Q28iYCWzNHjAm+yEAot5QaAMxhMghWLFVf7rRdwhUI+c2jix2DUXjAHXVi+s1ibs3mjPO/cCgbA++3BjD0vP/A==", "dependencies": { "follow-redirects": "^1.15.0", "form-data": "^4.0.0", @@ -1516,9 +1528,9 @@ "dev": true }, "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -1874,9 +1886,9 @@ } }, "node_modules/cypress": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.2.0.tgz", - "integrity": "sha512-AvDQxBydE771GTq0TR4ZUBvv9m9ffXuB/ueEtpDF/6gOcvFR96amgwSJP16Yhqw6VhmwqspT5nAGzoxxB+D89g==", + "version": "13.3.1", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.3.1.tgz", + "integrity": "sha512-g4mJLZxYN+UAF2LMy3Znd4LBnUmS59Vynd81VES59RdW48Yt+QtR2cush3melOoVNz0PPbADpWr8DcUx6mif8Q==", "dev": true, "hasInstallScript": true, "dependencies": { @@ -1932,9 +1944,9 @@ } }, "node_modules/cypress/node_modules/@types/node": { - "version": "18.17.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", - "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==", + "version": "18.18.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.5.tgz", + "integrity": "sha512-4slmbtwV59ZxitY4ixUZdy1uRLf9eSIvBWPQxNjhHYWEtn0FryfKpyS2cvADYXTayWdKEIsJengncrVvkI4I6A==", "dev": true }, "node_modules/cypress/node_modules/ansi-styles": { @@ -2044,9 +2056,9 @@ } }, "node_modules/dayjs": { - "version": "1.11.9", - "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", - "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==", + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==", "dev": true }, "node_modules/debug": { @@ -2446,9 +2458,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.15.2", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", - "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", + "version": "1.15.3", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.3.tgz", + "integrity": "sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==", "funding": [ { "type": "individual", @@ -2528,10 +2540,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/get-caller-file": { "version": "2.0.5", @@ -2660,13 +2675,10 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", + "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, "engines": { "node": ">= 0.4.0" } @@ -3024,9 +3036,9 @@ "dev": true }, "node_modules/itk-wasm": { - "version": "1.0.0-b.142", - "resolved": "https://registry.npmjs.org/itk-wasm/-/itk-wasm-1.0.0-b.142.tgz", - "integrity": "sha512-EMtl91UuG1GhPgPDhHVKsc404OIAevAk0LnglLS4VqSt5cGozgyx6Kx9wdZxw6b0+pTKjJjOiCZsElUCoUzn4Q==", + "version": "1.0.0-b.149", + "resolved": "https://registry.npmjs.org/itk-wasm/-/itk-wasm-1.0.0-b.149.tgz", + "integrity": "sha512-G1wvURAGMz/0XjHK1TKb4dZLwMV4+zsUZcuEkokH2fVtxWotj93OL3mrJvs7fhQ0Jenusf4COFN4yZ9Xt37SEA==", "dependencies": { "@babel/runtime": "^7.15.4", "@thewtex/zstddec": "^0.1.2", @@ -3066,9 +3078,9 @@ } }, "node_modules/joi": { - "version": "17.10.1", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.10.1.tgz", - "integrity": "sha512-vIiDxQKmRidUVp8KngT8MZSOcmRVm2zV7jbMjNYWuHcJWI0bUck3nRTGQjhpPlQenIQIBC5Vp9AhcnHbWQqafw==", + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", "dev": true, "dependencies": { "@hapi/hoek": "^9.0.0", @@ -4284,9 +4296,9 @@ "dev": true }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -4408,9 +4420,9 @@ } }, "node_modules/rollup": { - "version": "3.29.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.1.tgz", - "integrity": "sha512-c+ebvQz0VIH4KhhCpDsI+Bik0eT8ZFEVZEYw0cGMVqIP8zc+gnwl7iXCamTw7vzv2MeuZFZfdx5JJIq+ehzDlg==", + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, "bin": { "rollup": "dist/bin/rollup" @@ -4828,9 +4840,9 @@ } }, "node_modules/smob": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.0.tgz", - "integrity": "sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/smob/-/smob-1.4.1.tgz", + "integrity": "sha512-9LK+E7Hv5R9u4g4C3p+jjLstaLe11MDsL21UpYaCNmapvMkYhqCV4A/f/3gyH8QjMyh6l68q9xC85vihY9ahMQ==", "dev": true }, "node_modules/source-map": { @@ -4926,9 +4938,9 @@ } }, "node_modules/start-server-and-test": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.0.tgz", - "integrity": "sha512-UqKLw0mJbfrsG1jcRLTUlvuRi9sjNuUiDOLI42r7R5fA9dsFoywAy9DoLXNYys9B886E4RCKb+qM1Gzu96h7DQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.1.tgz", + "integrity": "sha512-8PFo4DLLLCDMuS51/BEEtE1m9CAXw1LNVtZSS1PzkYQh6Qf9JUwM4huYeSoUumaaoAyuwYBwCa9OsrcpMqcOdQ==", "dev": true, "dependencies": { "arg": "^5.0.2", @@ -4946,7 +4958,7 @@ "start-test": "src/bin/start.js" }, "engines": { - "node": ">=6" + "node": ">=16" } }, "node_modules/start-server-and-test/node_modules/execa": { @@ -5092,9 +5104,9 @@ } }, "node_modules/terser": { - "version": "5.19.4", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.19.4.tgz", - "integrity": "sha512-6p1DjHeuluwxDXcuT9VR8p64klWJKo1ILiy19s6C9+0Bh2+NWTX6nD9EPppiER4ICkHDVB1RkVpin/YW2nQn/g==", + "version": "5.21.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.21.0.tgz", + "integrity": "sha512-WtnFKrxu9kaoXuiZFSGrcAvvBqAdmKx0SFNmVNYdJamMu9yyN3I/QF0FbH4QcqJQ+y1CJnzxGIKH0cSj+FGYRw==", "dev": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", @@ -5233,6 +5245,12 @@ "node": ">=14.17" } }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -5284,9 +5302,9 @@ } }, "node_modules/vite": { - "version": "4.4.9", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz", - "integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==", + "version": "4.4.11", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.4.11.tgz", + "integrity": "sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==", "dev": true, "dependencies": { "esbuild": "^0.18.10", @@ -5339,9 +5357,9 @@ } }, "node_modules/vite-plugin-static-copy": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-0.14.0.tgz", - "integrity": "sha512-RMFmb4czomcrsbQBiUZs9HcDGN3kxGvF+OrtkfTVocp12CuoUCuJQhcY26RK35A6KS4WasGzEwcYZqHMjkAvVw==", + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/vite-plugin-static-copy/-/vite-plugin-static-copy-0.17.0.tgz", + "integrity": "sha512-2HpNbHfDt8SDy393AGXh9llHkc8FJMQkI8s3T5WsH3SWLMO+f5cFIyPErl4yGKU9Uh3Vaqsd4lHZYTf042fQ2A==", "dev": true, "dependencies": { "chokidar": "^3.5.3", diff --git a/packages/compress-stringify/typescript/package.json b/packages/compress-stringify/typescript/package.json index 79e3e9500..22e395829 100644 --- a/packages/compress-stringify/typescript/package.json +++ b/packages/compress-stringify/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@itk-wasm/compress-stringify", - "version": "0.6.1", + "version": "1.0.0", "description": "Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.", "type": "module", "module": "./dist/bundles/compress-stringify.js", @@ -39,7 +39,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.142" + "itk-wasm": "^1.0.0-b.149" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.0.0", @@ -50,7 +50,7 @@ "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", "ava": "^5.1.0", - "cypress": "^13.2.0", + "cypress": "^13.3.1", "rollup": "^3.9.0", "rollup-plugin-copy": "^3.4.0", "rollup-plugin-ignore": "^1.0.10", @@ -60,8 +60,8 @@ "supports-color": "^9.3.1", "tslib": "^2.5.2", "typescript": "^5.0.4", - "vite": "^4.3.3", - "vite-plugin-static-copy": "^0.14.0" + "vite": "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" }, "repository": { "type": "git", diff --git a/packages/compress-stringify/typescript/src/compress-stringify-node.ts b/packages/compress-stringify/typescript/src/compress-stringify-node.ts index 6011436ae..c7d437689 100644 --- a/packages/compress-stringify/typescript/src/compress-stringify-node.ts +++ b/packages/compress-stringify/typescript/src/compress-stringify-node.ts @@ -11,7 +11,6 @@ import { import CompressStringifyOptions from './compress-stringify-options.js' import CompressStringifyNodeResult from './compress-stringify-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function compressStringifyNode( } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'compress-stringify') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'compress-stringify') const { returnValue, diff --git a/packages/compress-stringify/typescript/src/compress-stringify.ts b/packages/compress-stringify/typescript/src/compress-stringify.ts index cfdb4d8aa..eb876d4ff 100644 --- a/packages/compress-stringify/typescript/src/compress-stringify.ts +++ b/packages/compress-stringify/typescript/src/compress-stringify.ts @@ -11,7 +11,6 @@ import { import CompressStringifyOptions from './compress-stringify-options.js' import CompressStringifyResult from './compress-stringify-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -24,7 +23,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function compressStringify( - webWorker: null | Worker, + webWorker: null | Worker | boolean, input: Uint8Array, options: CompressStringifyOptions = {} ) : Promise { diff --git a/packages/compress-stringify/typescript/src/index.ts b/packages/compress-stringify/typescript/src/index.ts index 8196bc415..ed3454294 100644 --- a/packages/compress-stringify/typescript/src/index.ts +++ b/packages/compress-stringify/typescript/src/index.ts @@ -1,7 +1,6 @@ // Generated file. To retain edits, remove this comment. export * from './pipelines-base-url.js' -export * from './pipeline-worker-url.js' import CompressStringifyResult from './compress-stringify-result.js' diff --git a/packages/compress-stringify/typescript/src/parse-string-decompress-node.ts b/packages/compress-stringify/typescript/src/parse-string-decompress-node.ts index ee918958e..a9cf75a8e 100644 --- a/packages/compress-stringify/typescript/src/parse-string-decompress-node.ts +++ b/packages/compress-stringify/typescript/src/parse-string-decompress-node.ts @@ -11,7 +11,6 @@ import { import ParseStringDecompressOptions from './parse-string-decompress-options.js' import ParseStringDecompressNodeResult from './parse-string-decompress-node-result.js' - import path from 'path' /** @@ -50,7 +49,7 @@ async function parseStringDecompressNode( options.parseString && args.push('--parse-string') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'parse-string-decompress') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'parse-string-decompress') const { returnValue, diff --git a/packages/compress-stringify/typescript/src/parse-string-decompress.ts b/packages/compress-stringify/typescript/src/parse-string-decompress.ts index 3fb53c908..36b44aac2 100644 --- a/packages/compress-stringify/typescript/src/parse-string-decompress.ts +++ b/packages/compress-stringify/typescript/src/parse-string-decompress.ts @@ -11,7 +11,6 @@ import { import ParseStringDecompressOptions from './parse-string-decompress-options.js' import ParseStringDecompressResult from './parse-string-decompress-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -24,7 +23,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function parseStringDecompress( - webWorker: null | Worker, + webWorker: null | Worker | boolean, input: Uint8Array, options: ParseStringDecompressOptions = {} ) : Promise { diff --git a/packages/compress-stringify/typescript/test/browser/demo-app/compress-stringify-controller.ts b/packages/compress-stringify/typescript/test/browser/demo-app/compress-stringify-controller.ts index fea29513b..b18da8d58 100644 --- a/packages/compress-stringify/typescript/test/browser/demo-app/compress-stringify-controller.ts +++ b/packages/compress-stringify/typescript/test/browser/demo-app/compress-stringify-controller.ts @@ -1,6 +1,6 @@ // Generated file. To retain edits, remove this comment. -import * as compressStringify from '../../../dist/bundles/compress-stringify.js' +import * as compressStringify from '../../../dist/index.js' import compressStringifyLoadSampleInputs, { usePreRun } from "./compress-stringify-load-sample-inputs.js" class CompressStringifyModel { diff --git a/packages/compress-stringify/typescript/test/browser/demo-app/index.ts b/packages/compress-stringify/typescript/test/browser/demo-app/index.ts index 93e7b60ff..993c203ed 100644 --- a/packages/compress-stringify/typescript/test/browser/demo-app/index.ts +++ b/packages/compress-stringify/typescript/test/browser/demo-app/index.ts @@ -1,12 +1,10 @@ // Generated file. To retain edits, remove this comment. -import * as compressStringify from '../../../dist/bundles/compress-stringify.js' +import * as compressStringify from '../../../dist/index.js' // Use local, vendored WebAssembly module assets const pipelinesBaseUrl: string | URL = new URL('/pipelines', document.location.origin).href compressStringify.setPipelinesBaseUrl(pipelinesBaseUrl) -const pipelineWorkerUrl: string | URL | null = new URL('/web-workers/itk-wasm-pipeline.worker.js', document.location.origin).href -compressStringify.setPipelineWorkerUrl(pipelineWorkerUrl) const params = new URLSearchParams(window.location.search) @@ -18,3 +16,4 @@ if (!params.has('functionName')) { } import './compress-stringify-controller.js' import './parse-string-decompress-controller.js' + diff --git a/packages/compress-stringify/typescript/test/browser/demo-app/parse-string-decompress-controller.ts b/packages/compress-stringify/typescript/test/browser/demo-app/parse-string-decompress-controller.ts index 0fd0f9a24..60781e38a 100644 --- a/packages/compress-stringify/typescript/test/browser/demo-app/parse-string-decompress-controller.ts +++ b/packages/compress-stringify/typescript/test/browser/demo-app/parse-string-decompress-controller.ts @@ -1,6 +1,6 @@ // Generated file. To retain edits, remove this comment. -import * as compressStringify from '../../../dist/bundles/compress-stringify.js' +import * as compressStringify from '../../../dist/index.js' import parseStringDecompressLoadSampleInputs, { usePreRun } from "./parse-string-decompress-load-sample-inputs.js" class ParseStringDecompressModel { diff --git a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py index 88c513ea3..ce1305bf4 100644 --- a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py +++ b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py @@ -1 +1 @@ -__version__ = "3.3.0" +__version__ = "4.0.0" diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py index 88c513ea3..ce1305bf4 100644 --- a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py +++ b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py @@ -1 +1 @@ -__version__ = "3.3.0" +__version__ = "4.0.0" diff --git a/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py index 88c513ea3..ce1305bf4 100644 --- a/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py +++ b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py @@ -1 +1 @@ -__version__ = "3.3.0" +__version__ = "4.0.0" diff --git a/packages/dicom/typescript/build/vite.config.js b/packages/dicom/typescript/build/vite.config.js index f40d37493..222e14626 100644 --- a/packages/dicom/typescript/build/vite.config.js +++ b/packages/dicom/typescript/build/vite.config.js @@ -13,7 +13,6 @@ export default defineConfig({ viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../dist/web-workers/*', dest: 'web-workers' }, ], }) ], diff --git a/packages/dicom/typescript/package.json b/packages/dicom/typescript/package.json index 92cfc506f..9a97505a5 100644 --- a/packages/dicom/typescript/package.json +++ b/packages/dicom/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@itk-wasm/dicom", - "version": "3.3.0", + "version": "4.0.0", "description": "Read files and images related to DICOM file format.", "type": "module", "module": "./dist/bundles/dicom.js", @@ -39,7 +39,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.138" + "itk-wasm": "^1.0.0-b.149" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.0.0", @@ -51,7 +51,7 @@ "@types/node": "^20.2.5", "ava": "^5.1.0", "cypress": "^12.17.2", - "itk-image-io": "^1.0.0-b.130", + "itk-image-io": "^1.0.0-b.149", "rollup": "^3.9.0", "rollup-plugin-copy": "^3.4.0", "rollup-plugin-ignore": "^1.0.10", diff --git a/packages/dicom/typescript/src/apply-presentation-state-to-image-node.ts b/packages/dicom/typescript/src/apply-presentation-state-to-image-node.ts index 7b3c58479..bb625eaa1 100644 --- a/packages/dicom/typescript/src/apply-presentation-state-to-image-node.ts +++ b/packages/dicom/typescript/src/apply-presentation-state-to-image-node.ts @@ -12,7 +12,6 @@ import { import ApplyPresentationStateToImageOptions from './apply-presentation-state-to-image-options.js' import ApplyPresentationStateToImageNodeResult from './apply-presentation-state-to-image-node-result.js' - import path from 'path' /** @@ -79,7 +78,7 @@ async function applyPresentationStateToImageNode( options.noBitmapOutput && args.push('--no-bitmap-output') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'apply-presentation-state-to-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'apply-presentation-state-to-image') const { returnValue, diff --git a/packages/dicom/typescript/src/apply-presentation-state-to-image.ts b/packages/dicom/typescript/src/apply-presentation-state-to-image.ts index 0af6d61b5..46726c410 100644 --- a/packages/dicom/typescript/src/apply-presentation-state-to-image.ts +++ b/packages/dicom/typescript/src/apply-presentation-state-to-image.ts @@ -13,7 +13,6 @@ import { import ApplyPresentationStateToImageOptions from './apply-presentation-state-to-image-options.js' import ApplyPresentationStateToImageResult from './apply-presentation-state-to-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function applyPresentationStateToImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, imageIn: File | BinaryFile, presentationStateFile: File | BinaryFile, options: ApplyPresentationStateToImageOptions = {} diff --git a/packages/dicom/typescript/src/read-dicom-encapsulated-pdf-node.ts b/packages/dicom/typescript/src/read-dicom-encapsulated-pdf-node.ts index 466314556..587c3bc84 100644 --- a/packages/dicom/typescript/src/read-dicom-encapsulated-pdf-node.ts +++ b/packages/dicom/typescript/src/read-dicom-encapsulated-pdf-node.ts @@ -11,7 +11,6 @@ import { import ReadDicomEncapsulatedPdfOptions from './read-dicom-encapsulated-pdf-options.js' import ReadDicomEncapsulatedPdfNodeResult from './read-dicom-encapsulated-pdf-node-result.js' - import path from 'path' /** @@ -95,7 +94,7 @@ async function readDicomEncapsulatedPdfNode( options.disableCorrection && args.push('--disable-correction') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'read-dicom-encapsulated-pdf') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'read-dicom-encapsulated-pdf') const { returnValue, diff --git a/packages/dicom/typescript/src/read-dicom-encapsulated-pdf.ts b/packages/dicom/typescript/src/read-dicom-encapsulated-pdf.ts index de43f1dbd..383cd2fec 100644 --- a/packages/dicom/typescript/src/read-dicom-encapsulated-pdf.ts +++ b/packages/dicom/typescript/src/read-dicom-encapsulated-pdf.ts @@ -12,7 +12,6 @@ import { import ReadDicomEncapsulatedPdfOptions from './read-dicom-encapsulated-pdf-options.js' import ReadDicomEncapsulatedPdfResult from './read-dicom-encapsulated-pdf-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -25,7 +24,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function readDicomEncapsulatedPdf( - webWorker: null | Worker, + webWorker: null | Worker | boolean, dicomFile: File | BinaryFile, options: ReadDicomEncapsulatedPdfOptions = {} ) : Promise { diff --git a/packages/dicom/typescript/src/read-image-dicom-file-series-node.ts b/packages/dicom/typescript/src/read-image-dicom-file-series-node.ts index b038dfc01..a97e59cd0 100644 --- a/packages/dicom/typescript/src/read-image-dicom-file-series-node.ts +++ b/packages/dicom/typescript/src/read-image-dicom-file-series-node.ts @@ -12,7 +12,6 @@ import { import ReadImageDicomFileSeriesOptions from './read-image-dicom-file-series-options.js' import ReadImageDicomFileSeriesNodeResult from './read-image-dicom-file-series-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function readImageDicomFileSeriesNode( options.singleSortedSeries && args.push('--single-sorted-series') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'read-image-dicom-file-series') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'read-image-dicom-file-series') const { returnValue, diff --git a/packages/dicom/typescript/src/structured-report-to-html-node.ts b/packages/dicom/typescript/src/structured-report-to-html-node.ts index bc5c2f309..bf1bacbaf 100644 --- a/packages/dicom/typescript/src/structured-report-to-html-node.ts +++ b/packages/dicom/typescript/src/structured-report-to-html-node.ts @@ -11,7 +11,6 @@ import { import StructuredReportToHtmlOptions from './structured-report-to-html-options.js' import StructuredReportToHtmlNodeResult from './structured-report-to-html-node-result.js' - import path from 'path' /** @@ -181,7 +180,7 @@ async function structuredReportToHtmlNode( options.codeDetailsTooltip && args.push('--code-details-tooltip') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'structured-report-to-html') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'structured-report-to-html') const { returnValue, diff --git a/packages/dicom/typescript/src/structured-report-to-html.ts b/packages/dicom/typescript/src/structured-report-to-html.ts index 9ef684a2b..4ab809943 100644 --- a/packages/dicom/typescript/src/structured-report-to-html.ts +++ b/packages/dicom/typescript/src/structured-report-to-html.ts @@ -13,7 +13,6 @@ import { import StructuredReportToHtmlOptions from './structured-report-to-html-options.js' import StructuredReportToHtmlResult from './structured-report-to-html-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function structuredReportToHtml( - webWorker: null | Worker, + webWorker: null | Worker | boolean, dicomFile: File | BinaryFile, options: StructuredReportToHtmlOptions = {} ) : Promise { diff --git a/packages/dicom/typescript/src/structured-report-to-text-node.ts b/packages/dicom/typescript/src/structured-report-to-text-node.ts index bab2b3ec8..1460393d9 100644 --- a/packages/dicom/typescript/src/structured-report-to-text-node.ts +++ b/packages/dicom/typescript/src/structured-report-to-text-node.ts @@ -11,7 +11,6 @@ import { import StructuredReportToTextOptions from './structured-report-to-text-options.js' import StructuredReportToTextNodeResult from './structured-report-to-text-node-result.js' - import path from 'path' /** @@ -101,7 +100,7 @@ async function structuredReportToTextNode( options.printColor && args.push('--print-color') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'structured-report-to-text') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'structured-report-to-text') const { returnValue, diff --git a/packages/dicom/typescript/src/structured-report-to-text.ts b/packages/dicom/typescript/src/structured-report-to-text.ts index b01801138..cd2467298 100644 --- a/packages/dicom/typescript/src/structured-report-to-text.ts +++ b/packages/dicom/typescript/src/structured-report-to-text.ts @@ -12,7 +12,6 @@ import { import StructuredReportToTextOptions from './structured-report-to-text-options.js' import StructuredReportToTextResult from './structured-report-to-text-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -25,7 +24,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function structuredReportToText( - webWorker: null | Worker, + webWorker: null | Worker | boolean, dicomFile: File | BinaryFile, options: StructuredReportToTextOptions = {} ) : Promise { diff --git a/packages/dicom/typescript/test/browser/demo-app/apply-presentation-state-to-image-controller.ts b/packages/dicom/typescript/test/browser/demo-app/apply-presentation-state-to-image-controller.ts index afa10fcb1..10127aa8a 100644 --- a/packages/dicom/typescript/test/browser/demo-app/apply-presentation-state-to-image-controller.ts +++ b/packages/dicom/typescript/test/browser/demo-app/apply-presentation-state-to-image-controller.ts @@ -1,8 +1,8 @@ // Generated file. To retain edits, remove this comment. -import { writeImageArrayBuffer } from 'itk-wasm' +import { writeImage } from '@itk-wasm/image-io' import { copyImage } from 'itk-wasm' -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' import applyPresentationStateToImageLoadSampleInputs, { usePreRun } from "./apply-presentation-state-to-image-load-sample-inputs.js" class ApplyPresentationStateToImageModel { @@ -111,10 +111,10 @@ class ApplyPresentationStateToImageController { const outputImageDownloadFormat = document.getElementById('output-image-output-format') const downloadFormat = outputImageDownloadFormat.value || 'nrrd' const fileName = `outputImage.${downloadFormat}` - const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("outputImage")), fileName) + const { webWorker, serializedImage } = await writeImage(null, copyImage(model.outputs.get("outputImage")), fileName) webWorker.terminate() - globalThis.downloadFile(arrayBuffer, fileName) + globalThis.downloadFile(serializedImage, fileName) } }) diff --git a/packages/dicom/typescript/test/browser/demo-app/index.ts b/packages/dicom/typescript/test/browser/demo-app/index.ts index 69caa9fe0..3afd1b147 100644 --- a/packages/dicom/typescript/test/browser/demo-app/index.ts +++ b/packages/dicom/typescript/test/browser/demo-app/index.ts @@ -1,12 +1,10 @@ // Generated file. To retain edits, remove this comment. -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' // Use local, vendored WebAssembly module assets const pipelinesBaseUrl: string | URL = new URL('/pipelines', document.location.origin).href dicom.setPipelinesBaseUrl(pipelinesBaseUrl) -const pipelineWorkerUrl: string | URL | null = new URL('/web-workers/itk-wasm-pipeline.worker.js', document.location.origin).href -dicom.setPipelineWorkerUrl(pipelineWorkerUrl) const params = new URLSearchParams(window.location.search) @@ -22,3 +20,4 @@ import './structured-report-to-html-controller.js' import './structured-report-to-text-controller.js' import './read-dicom-tags-controller.js' import './read-image-dicom-file-series-controller.js' + diff --git a/packages/dicom/typescript/test/browser/demo-app/read-dicom-tags-controller.ts b/packages/dicom/typescript/test/browser/demo-app/read-dicom-tags-controller.ts index fe175a0a2..e79edc3d2 100644 --- a/packages/dicom/typescript/test/browser/demo-app/read-dicom-tags-controller.ts +++ b/packages/dicom/typescript/test/browser/demo-app/read-dicom-tags-controller.ts @@ -1,6 +1,6 @@ // Generated file. To retain edits, remove this comment. -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' import readDicomTagsLoadSampleInputs, { usePreRun } from "./read-dicom-tags-load-sample-inputs.js" class ReadDicomTagsModel { diff --git a/packages/dicom/typescript/test/browser/demo-app/structured-report-to-text-controller.ts b/packages/dicom/typescript/test/browser/demo-app/structured-report-to-text-controller.ts index e166c8c1b..50b233f78 100644 --- a/packages/dicom/typescript/test/browser/demo-app/structured-report-to-text-controller.ts +++ b/packages/dicom/typescript/test/browser/demo-app/structured-report-to-text-controller.ts @@ -1,6 +1,6 @@ // Generated file. To retain edits, remove this comment. -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' import structuredReportToTextLoadSampleInputs, { usePreRun } from "./structured-report-to-text-load-sample-inputs.js" class StructuredReportToTextModel { diff --git a/packages/image-io/typescript/.npmignore b/packages/image-io/typescript/.npmignore index ff327591c..4ef5735e4 100644 --- a/packages/image-io/typescript/.npmignore +++ b/packages/image-io/typescript/.npmignore @@ -2,4 +2,5 @@ node_modules .DS_Store test cypress -demo-app \ No newline at end of file +demo-app +demo-app-rollup diff --git a/packages/image-io/typescript/README.md b/packages/image-io/typescript/README.md index 0ad785cb5..d29d798c8 100644 --- a/packages/image-io/typescript/README.md +++ b/packages/image-io/typescript/README.md @@ -18,13 +18,83 @@ Import: ```js import { + readImage + writeImage setPipelinesBaseUrl, getPipelinesBaseUrl, - setPipelineWorkerUrl, - getPipelineWorkerUrl, } from "@itk-wasm/image-io" ``` +#### readImage + +*Read an image file format and convert it to an itk-wasm Image.* + +```ts +async function readImage( + webWorker: null | Worker, + serializedImage: File | BinaryFile, + options: ReadImageOptions = {} +) : Promise +``` + +| Parameter | Type | Description | +| :---------------: | :-----------------: | :---------------------------------------- | +| `webWorker` | *null or Worker* | WebWorker to use for computation. Set to null to create a new worker. Or, pass an existing worker. | +| `serializedImage` | *File or BinaryFile* | Input image serialized in the file format. | + +**`ReadImageOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :-------------------------------------------------- | +| `informationOnly` | *boolean* | Only read image metadata -- do not read pixel data. | +| `componentType` | *typeof IntTypes or typeof FloatTypes* | Component type, from itk-wasm IntTypes, FloatTypes, for the output pixel components. Defaults to the input component type. | +| `pixelType` | *typeof PixelTypes* | Pixel type, from itk-wasm PixelTypes, for the output pixels. Defaults to the input pixel type. | + +**`ReadImageResult` interface:** + +| Property | Type | Description | +| :-----------: | :--------------: | :------------------------------------------------------------------------ | +| `webWorker` | *Worker* | WebWorker used for computation | +| `image` | *Image* | Output image | + +#### writeImage + +*Write an itk-wasm Image converted to an image file format* + +```ts +async function writeImage( + webWorker: null | Worker, + image: Image, + serializedImage: string, + options: WriteImageOptions = {} +) : Promise +``` + +| Parameter | Type | Description | +| :---------------: | :------: | :------------------------------------------ | +| `webWorker` | *null or Worker* | WebWorker to use for computation. Set to null to create a new worker. Or, pass an existing worker. | +| `image` | *Image* | Input image | +| `serializedImage` | *string* | Output image serialized in the file format. | + +**`WriteImageOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :---------------------------------------------------- | +| `informationOnly` | *boolean* | Only write image metadata -- do not write pixel data. | +| `useCompression` | *boolean* | Use compression in the written file | +| `mimeType` | *string* | Mime type of the output image file. | +| `componentType` | *typeof IntTypes or typeof FloatTypes* | Component type, from itk-wasm IntTypes, FloatTypes, for the output pixel components. Defaults to the input component type. | +| `pixelType` | *typeof PixelTypes* | Pixel type, from itk-wasm PixelTypes, for the output pixels. Defaults to the input pixel type. | + +**`WriteImageResult` interface:** + +| Property | Type | Description | +| :---------------: | :--------------: | :--------------------------------------------------------------------------- | +| `webWorker` | *Worker* | WebWorker used for computation | +| `serializedImage` | *BinaryFile* | Output image serialized in the file format. | + + + #### setPipelinesBaseUrl *Set base URL for WebAssembly assets when vendored.* @@ -43,33 +113,205 @@ function setPipelinesBaseUrl( function getPipelinesBaseUrl() : string | URL ``` -#### setPipelineWorkerUrl +Additional per-format functions are available, but they are usually not used directly. Example interface for the *BioRad* format: + +#### bioRadReadImage -*Set base URL for the itk-wasm pipeline worker script when vendored.* +*Read an image file format and convert it to the itk-wasm file format* ```ts -function setPipelineWorkerUrl( - baseUrl: string | URL -) : void +async function bioRadReadImage( + webWorker: null | Worker, + serializedImage: File | BinaryFile, + options: BioRadReadImageOptions = {} +) : Promise ``` -#### getPipelineWorkerUrl +| Parameter | Type | Description | +| :---------------: | :-----------------: | :---------------------------------------- | +| `serializedImage` | *File or BinaryFile* | Input image serialized in the file format | + +**`BioRadReadImageOptions` interface:** -*Get base URL for the itk-wasm pipeline worker script when vendored.* +| Property | Type | Description | +| :---------------: | :-------: | :-------------------------------------------------- | +| `informationOnly` | *boolean* | Only read image metadata -- do not read pixel data. | + +**`BioRadReadImageResult` interface:** + +| Property | Type | Description | +| :-----------: | :--------------: | :------------------------------------------------------------------------ | +| `webWorker` | *Worker* | WebWorker used for computation | +| `couldRead` | *JsonCompatible* | Whether the input could be read. If false, the output image is not valid. | +| `image` | *Image* | Output image | + +#### bioRadWriteImage + +*Write an itk-wasm file format converted to an image file format* ```ts -function getPipelineWorkerUrl() : string | URL +async function bioRadWriteImage( + webWorker: null | Worker, + image: Image, + serializedImage: string, + options: BioRadWriteImageOptions = {} +) : Promise ``` +| Parameter | Type | Description | +| :---------------: | :------: | :------------------------------------------ | +| `image` | *Image* | Input image | +| `serializedImage` | *string* | Output image serialized in the file format. | + +**`BioRadWriteImageOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :---------------------------------------------------- | +| `informationOnly` | *boolean* | Only write image metadata -- do not write pixel data. | +| `useCompression` | *boolean* | Use compression in the written file | + +**`BioRadWriteImageResult` interface:** + +| Property | Type | Description | +| :---------------: | :--------------: | :--------------------------------------------------------------------------- | +| `webWorker` | *Worker* | WebWorker used for computation | +| `couldWrite` | *JsonCompatible* | Whether the input could be written. If false, the output image is not valid. | +| `serializedImage` | *BinaryFile* | Output image serialized in the file format. | + + ### Node interface Import: ```js import { - setPipelinesBaseUrl, - getPipelinesBaseUrl, - setPipelineWorkerUrl, - getPipelineWorkerUrl, + readImageNode, + writeImageNode, } from "@itk-wasm/image-io" ``` + +#### readImageNode + +*Read an image file format and convert it to an itk-wasm Image.* + +```ts +async function readImageNode( + serializedImage: File | BinaryFile, + options: ReadImageOptions = {} +) : Promise +``` + +| Parameter | Type | Description | +| :---------------: | :-----------------: | :---------------------------------------- | +| `serializedImage` | *File or BinaryFile* | Input image serialized in the file format. | + +**`ReadImageOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :-------------------------------------------------- | +| `informationOnly` | *boolean* | Only read image metadata -- do not read pixel data. | +| `componentType` | *typeof IntTypes or typeof FloatTypes* | Component type, from itk-wasm IntTypes, FloatTypes, for the output pixel components. Defaults to the input component type. | +| `pixelType` | *typeof PixelTypes* | Pixel type, from itk-wasm PixelTypes, for the output pixels. Defaults to the input pixel type. | + +**`ReadImageResult` interface:** + +| Property | Type | Description | +| :-----------: | :--------------: | :------------------------------------------------------------------------ | +| `image` | *Image* | Output image | + +#### writeImageNode + +*Write an itk-wasm Image converted to an image file format* + +```ts +async function writeImageNode( + image: Image, + serializedImage: string, + options: WriteImageOptions = {} +) : Promise +``` + +| Parameter | Type | Description | +| :---------------: | :------: | :------------------------------------------ | +| `image` | *Image* | Input image | +| `serializedImage` | *string* | Output image serialized in the file format. | + +**`WriteImageOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :---------------------------------------------------- | +| `informationOnly` | *boolean* | Only write image metadata -- do not write pixel data. | +| `useCompression` | *boolean* | Use compression in the written file | +| `mimeType` | *string* | Mime type of the output image file. | +| `componentType` | *typeof IntTypes or typeof FloatTypes* | Component type, from itk-wasm IntTypes, FloatTypes, for the output pixel components. Defaults to the input component type. | +| `pixelType` | *typeof PixelTypes* | Pixel type, from itk-wasm PixelTypes, for the output pixels. Defaults to the input pixel type. | + +**`WriteImageResult` interface:** + +| Property | Type | Description | +| :---------------: | :--------------: | :--------------------------------------------------------------------------- | +| `serializedImage` | *BinaryFile* | Output image serialized in the file format. | + + + + +Additional per-format functions are available, but they are usually not used directly. Example interface for the *BioRad* format: + +#### bioRadReadImageNode + +*Read an image file format and convert it to the itk-wasm file format* + +```ts +async function bioRadReadImageNode( + serializedImage: string, + options: BioRadReadImageOptions = {} +) : Promise +``` + +| Parameter | Type | Description | +| :---------------: | :------: | :---------------------------------------- | +| `serializedImage` | *string* | Input image serialized in the file format | + +**`BioRadReadImageNodeOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :-------------------------------------------------- | +| `informationOnly` | *boolean* | Only read image metadata -- do not read pixel data. | + +**`BioRadReadImageNodeResult` interface:** + +| Property | Type | Description | +| :---------: | :--------------: | :------------------------------------------------------------------------ | +| `couldRead` | *JsonCompatible* | Whether the input could be read. If false, the output image is not valid. | +| `image` | *Image* | Output image | + +#### bioRadWriteImageNode + +*Write an itk-wasm file format converted to an image file format* + +```ts +async function bioRadWriteImageNode( + image: Image, + serializedImage: string, + options: BioRadWriteImageOptions = {} +) : Promise +``` + +| Parameter | Type | Description | +| :---------------: | :------: | :------------------------------------------ | +| `image` | *Image* | Input image | +| `serializedImage` | *string* | Output image serialized in the file format. | + +**`BioRadWriteImageNodeOptions` interface:** + +| Property | Type | Description | +| :---------------: | :-------: | :---------------------------------------------------- | +| `informationOnly` | *boolean* | Only write image metadata -- do not write pixel data. | +| `useCompression` | *boolean* | Use compression in the written file | + +**`BioRadWriteImageNodeResult` interface:** + +| Property | Type | Description | +| :---------------: | :--------------: | :--------------------------------------------------------------------------- | +| `couldWrite` | *JsonCompatible* | Whether the input could be written. If false, the output image is not valid. | +| `serializedImage` | *BinaryFile* | Output image serialized in the file format. | diff --git a/packages/image-io/typescript/build/rollup.browser.config.js b/packages/image-io/typescript/build/rollup.browser.config.js index ac03845a3..98ec279b6 100644 --- a/packages/image-io/typescript/build/rollup.browser.config.js +++ b/packages/image-io/typescript/build/rollup.browser.config.js @@ -1,5 +1,4 @@ import { nodeResolve } from '@rollup/plugin-node-resolve' -import copy from 'rollup-plugin-copy' import typescript from '@rollup/plugin-typescript' import commonjs from '@rollup/plugin-commonjs' import nodePolyfills from 'rollup-plugin-polyfill-node' @@ -8,27 +7,32 @@ import terser from '@rollup/plugin-terser' import packageJson from '../package.json' assert { type: 'json' } import json from '@rollup/plugin-json' import path from 'path' +import OMT from "@surma/rollup-plugin-off-main-thread" + +const omtCustom = OMT() +omtCustom.resolveImportMeta = () => { + return 'import.meta.url' +} -const itkConfig = './src/itkConfig.js' const bundleName = path.basename(packageJson.name) export default { input: './src/index.ts', output: [ { - file: `./dist/bundles/${bundleName}.js`, + dir: `./dist`, format: 'es', sourcemap: true, // plugins: [terser(),], }, ], + onwarn: function onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + if (warning.message.includes('Very few browsers support ES modules in Workers.')) return; + console.log('onwarn', warning) + warn(warning); + }, plugins: [ - copy({ - targets: [ - { src: 'node_modules/itk-wasm/dist/web-workers/bundles/pipeline.worker.js', dest: 'dist/web-workers/' }, - ], - hook: 'writeBundle' - }), ignore(['crypto']), nodeResolve({ preferBuiltins: false, @@ -40,12 +44,6 @@ export default { nodePolyfills(), typescript(), json(), - ], - resolve: { - // where itk-wasm code has 'import ../itkConfig.js` point to the path of itkConfig - alias: { - '../itkConfig.js': itkConfig, - '../../itkConfig.js': itkConfig - } - } + omtCustom, + ] } diff --git a/packages/image-io/typescript/build/rollup.node.config.js b/packages/image-io/typescript/build/rollup.node.config.js index 431b29d3e..57d19955d 100644 --- a/packages/image-io/typescript/build/rollup.node.config.js +++ b/packages/image-io/typescript/build/rollup.node.config.js @@ -12,12 +12,16 @@ export default { input: './src/index-node.ts', output: [ { - file: `./dist/bundles/${bundleName}-node.js`, + dir: './dist', format: 'es', sourcemap: true, // plugins: [terser(),], }, ], + onwarn: function onwarn(warning, warn) { + if (warning.code === 'THIS_IS_UNDEFINED') return; + warn(warning); + }, plugins: [ commonjs({ transformMixedEsModules: true diff --git a/packages/image-io/typescript/build/vite-rollup-watch.config.ts b/packages/image-io/typescript/build/vite-rollup-watch.config.ts new file mode 100644 index 000000000..ae3065c14 --- /dev/null +++ b/packages/image-io/typescript/build/vite-rollup-watch.config.ts @@ -0,0 +1,24 @@ +import { defineConfig } from 'vite' +import { generateConfig } from './vite.config' + +export default defineConfig(({ mode }) => { + const config: UserConfig = generateConfig({ mode }) + + config.preview = { + port: 5004, + } + + config.build = { + // Enable Rollup watcher @see https://vitejs.dev/config/#build-watch + watch: {}, + + // Opt for the fastest build + target: 'esnext', + minify: false, + rollupOptions: { ...config.build.rollupOptions, treeshake: false }, + + outDir: '../../../demo-app-rollup', + } + + return config +}) diff --git a/packages/image-io/typescript/build/vite.config.js b/packages/image-io/typescript/build/vite.config.js index f40d37493..7ef77ee3a 100644 --- a/packages/image-io/typescript/build/vite.config.js +++ b/packages/image-io/typescript/build/vite.config.js @@ -2,19 +2,26 @@ import { defineConfig } from 'vite' import { viteStaticCopy } from 'vite-plugin-static-copy' import path from 'path' -export default defineConfig({ - root: path.join('test', 'browser', 'demo-app'), - build: { - outDir: '../../../demo-app', - emptyOutDir: true, - }, - plugins: [ - // put lazy loaded JavaScript and Wasm bundles in dist directory - viteStaticCopy({ - targets: [ - { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../dist/web-workers/*', dest: 'web-workers' }, - ], - }) - ], -}) +export default defineConfig(generateConfig) + +export function generateConfig() { + return { + root: path.join('test', 'browser', 'demo-app'), + build: { + outDir: '../../../demo-app', + emptyOutDir: true, + chunkSizeWarningLimit: 800e6, + }, + worker: { + format: 'es' + }, + plugins: [ + // put lazy loaded JavaScript and Wasm bundles in dist directory + viteStaticCopy({ + targets: [ + { src: '../../../dist/pipelines/*', dest: 'pipelines' }, + ], + }) + ], + } +} diff --git a/packages/image-io/typescript/cypress.config.ts b/packages/image-io/typescript/cypress.config.ts index 6ddaef889..1d4054ee4 100644 --- a/packages/image-io/typescript/cypress.config.ts +++ b/packages/image-io/typescript/cypress.config.ts @@ -2,9 +2,8 @@ import { defineConfig } from "cypress"; export default defineConfig({ e2e: { - defaultCommandTimeout: 8000, + defaultCommandTimeout: 40000, setupNodeEvents(on, config) { - // implement node event listeners here }, }, }); diff --git a/packages/image-io/typescript/cypress/e2e/common.ts b/packages/image-io/typescript/cypress/e2e/common.ts index 4f712993a..76c8849d9 100644 --- a/packages/image-io/typescript/cypress/e2e/common.ts +++ b/packages/image-io/typescript/cypress/e2e/common.ts @@ -1 +1 @@ -export const demoServer = 'http://localhost:5173' +export const demoServer = 'http://localhost:5004' diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json index 96b9d3bf4..b9bb968cc 100644 --- a/packages/image-io/typescript/package.json +++ b/packages/image-io/typescript/package.json @@ -1,15 +1,16 @@ { "name": "@itk-wasm/image-io", - "version": "0.1.0", + "version": "0.3.0", "description": "Input and output for scientific and medical image file formats.", "type": "module", - "module": "./dist/bundles/image-io.js", - "types": "./dist/src/index.d.ts", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { - "browser": "./dist/bundles/image-io.js", - "node": "./dist/bundles/image-io.node.js", - "default": "./dist/bundles/image-io.js" + "types": "./dist/index.d.js", + "browser": "./dist/index.js", + "node": "./dist/index-node.js", + "default": "./dist/index.js" } }, "scripts": { @@ -17,19 +18,21 @@ "test": "npm run test:node && npm run test:browser", "test:node": "ava", "test:browser": "npm run test:browser:chrome && npm run test:browser:firefox", - "test:browser:firefox": "start-server-and-test start http-get://localhost:5173 cypress:runFirefox", - "test:browser:chrome": "start-server-and-test start http-get://localhost:5173 cypress:runChrome", - "test:browser:debug": "start-server-and-test start http-get://localhost:5173 cypress:open", + "test:browser:firefox": "start-server-and-test rollup:start http-get://localhost:5004 cypress:runFirefox", + "test:browser:chrome": "start-server-and-test rollup:start http-get://localhost:5004 cypress:runChrome", + "test:browser:debug": "start-server-and-test rollup:start http-get://localhost:5004 cypress:open", "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:browser:workerEmbedded && npm run build:demo", - "build:node": "esbuild --bundle --format=esm --banner:js=\"import { createRequire } from 'module';const require = createRequire(import.meta.url);\" --platform=node --outfile=./dist/index-node.js ./src/index-node.ts", - "build:browser": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/ && esbuild --bundle --format=esm --outfile=./dist/index.js ./src/index.ts", - "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build": "npm run build:tsc && npm run build:browser:webWorkers && npm run build:browser:workerEmbedded && npm run build:demo", + "build:browser:webWorkers": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/image-io-worker-embedded.js ./src/index-worker-embedded.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", - "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" + "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build", + "rollup:start": "npm run copyShoelaceAssets && concurrently npm:rollup:dev npm:rollup:preview", + "rollup:dev": "vite build --config build/vite-rollup-watch.config.ts", + "rollup:preview": "vite preview --config build/vite-rollup-watch.config.ts" }, "keywords": [ "itk", @@ -46,12 +49,14 @@ "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", "ava": "^5.3.1", + "concurrently": "^8.2.1", "cypress": "^13.3.0", "esbuild": "^0.19.5", "shx": "^0.3.4", + "start-server-and-test": "^2.0.1", "typescript": "^5.0.4", - "vite": "^4.3.3", - "vite-plugin-static-copy": "^0.14.0" + "vite": "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" }, "repository": { "type": "git", diff --git a/packages/image-io/typescript/src/bio-rad-read-image-node.ts b/packages/image-io/typescript/src/bio-rad-read-image-node.ts index 881e833dc..c0881c52a 100644 --- a/packages/image-io/typescript/src/bio-rad-read-image-node.ts +++ b/packages/image-io/typescript/src/bio-rad-read-image-node.ts @@ -12,7 +12,6 @@ import { import BioRadReadImageOptions from './bio-rad-read-image-options.js' import BioRadReadImageNodeResult from './bio-rad-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function bioRadReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'bio-rad-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'bio-rad-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/bio-rad-read-image.ts b/packages/image-io/typescript/src/bio-rad-read-image.ts index 6177af870..ebd2f916c 100644 --- a/packages/image-io/typescript/src/bio-rad-read-image.ts +++ b/packages/image-io/typescript/src/bio-rad-read-image.ts @@ -13,7 +13,6 @@ import { import BioRadReadImageOptions from './bio-rad-read-image-options.js' import BioRadReadImageResult from './bio-rad-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function bioRadReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: BioRadReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/bio-rad-write-image-node.ts b/packages/image-io/typescript/src/bio-rad-write-image-node.ts index 9a69f2c07..5e16912d9 100644 --- a/packages/image-io/typescript/src/bio-rad-write-image-node.ts +++ b/packages/image-io/typescript/src/bio-rad-write-image-node.ts @@ -12,7 +12,6 @@ import { import BioRadWriteImageOptions from './bio-rad-write-image-options.js' import BioRadWriteImageNodeResult from './bio-rad-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function bioRadWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'bio-rad-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'bio-rad-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/bio-rad-write-image.ts b/packages/image-io/typescript/src/bio-rad-write-image.ts index ec0722a82..09effb30f 100644 --- a/packages/image-io/typescript/src/bio-rad-write-image.ts +++ b/packages/image-io/typescript/src/bio-rad-write-image.ts @@ -13,7 +13,6 @@ import { import BioRadWriteImageOptions from './bio-rad-write-image-options.js' import BioRadWriteImageResult from './bio-rad-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function bioRadWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: BioRadWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/bmp-read-image-node.ts b/packages/image-io/typescript/src/bmp-read-image-node.ts index 308849204..de332259b 100644 --- a/packages/image-io/typescript/src/bmp-read-image-node.ts +++ b/packages/image-io/typescript/src/bmp-read-image-node.ts @@ -12,7 +12,6 @@ import { import BmpReadImageOptions from './bmp-read-image-options.js' import BmpReadImageNodeResult from './bmp-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function bmpReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'bmp-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'bmp-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/bmp-read-image.ts b/packages/image-io/typescript/src/bmp-read-image.ts index e9f30c637..0d08425a5 100644 --- a/packages/image-io/typescript/src/bmp-read-image.ts +++ b/packages/image-io/typescript/src/bmp-read-image.ts @@ -13,7 +13,6 @@ import { import BmpReadImageOptions from './bmp-read-image-options.js' import BmpReadImageResult from './bmp-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function bmpReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: BmpReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/bmp-write-image-node.ts b/packages/image-io/typescript/src/bmp-write-image-node.ts index 872e93234..f647dd0df 100644 --- a/packages/image-io/typescript/src/bmp-write-image-node.ts +++ b/packages/image-io/typescript/src/bmp-write-image-node.ts @@ -12,7 +12,6 @@ import { import BmpWriteImageOptions from './bmp-write-image-options.js' import BmpWriteImageNodeResult from './bmp-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function bmpWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'bmp-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'bmp-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/bmp-write-image.ts b/packages/image-io/typescript/src/bmp-write-image.ts index 92c25ea23..2d0eb72c9 100644 --- a/packages/image-io/typescript/src/bmp-write-image.ts +++ b/packages/image-io/typescript/src/bmp-write-image.ts @@ -13,7 +13,6 @@ import { import BmpWriteImageOptions from './bmp-write-image-options.js' import BmpWriteImageResult from './bmp-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function bmpWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: BmpWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/fdf-read-image-node.ts b/packages/image-io/typescript/src/fdf-read-image-node.ts index 31bc33d8b..0a6fc66ee 100644 --- a/packages/image-io/typescript/src/fdf-read-image-node.ts +++ b/packages/image-io/typescript/src/fdf-read-image-node.ts @@ -12,7 +12,6 @@ import { import FdfReadImageOptions from './fdf-read-image-options.js' import FdfReadImageNodeResult from './fdf-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function fdfReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'fdf-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'fdf-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/fdf-read-image.ts b/packages/image-io/typescript/src/fdf-read-image.ts index d77ed48fe..1914f4d73 100644 --- a/packages/image-io/typescript/src/fdf-read-image.ts +++ b/packages/image-io/typescript/src/fdf-read-image.ts @@ -13,7 +13,6 @@ import { import FdfReadImageOptions from './fdf-read-image-options.js' import FdfReadImageResult from './fdf-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function fdfReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: FdfReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/fdf-write-image-node.ts b/packages/image-io/typescript/src/fdf-write-image-node.ts index 7a2ba3c7b..353c1544d 100644 --- a/packages/image-io/typescript/src/fdf-write-image-node.ts +++ b/packages/image-io/typescript/src/fdf-write-image-node.ts @@ -12,7 +12,6 @@ import { import FdfWriteImageOptions from './fdf-write-image-options.js' import FdfWriteImageNodeResult from './fdf-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function fdfWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'fdf-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'fdf-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/fdf-write-image.ts b/packages/image-io/typescript/src/fdf-write-image.ts index 613c829a1..fea14cb59 100644 --- a/packages/image-io/typescript/src/fdf-write-image.ts +++ b/packages/image-io/typescript/src/fdf-write-image.ts @@ -13,7 +13,6 @@ import { import FdfWriteImageOptions from './fdf-write-image-options.js' import FdfWriteImageResult from './fdf-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function fdfWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: FdfWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/gdcm-read-image-node.ts b/packages/image-io/typescript/src/gdcm-read-image-node.ts index 233101e79..6904760c0 100644 --- a/packages/image-io/typescript/src/gdcm-read-image-node.ts +++ b/packages/image-io/typescript/src/gdcm-read-image-node.ts @@ -12,7 +12,6 @@ import { import GdcmReadImageOptions from './gdcm-read-image-options.js' import GdcmReadImageNodeResult from './gdcm-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function gdcmReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'gdcm-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'gdcm-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/gdcm-read-image.ts b/packages/image-io/typescript/src/gdcm-read-image.ts index a8c88fc1a..9794c809c 100644 --- a/packages/image-io/typescript/src/gdcm-read-image.ts +++ b/packages/image-io/typescript/src/gdcm-read-image.ts @@ -13,7 +13,6 @@ import { import GdcmReadImageOptions from './gdcm-read-image-options.js' import GdcmReadImageResult from './gdcm-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function gdcmReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: GdcmReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/gdcm-write-image-node.ts b/packages/image-io/typescript/src/gdcm-write-image-node.ts index 5fbd56db1..1b4b43d01 100644 --- a/packages/image-io/typescript/src/gdcm-write-image-node.ts +++ b/packages/image-io/typescript/src/gdcm-write-image-node.ts @@ -12,7 +12,6 @@ import { import GdcmWriteImageOptions from './gdcm-write-image-options.js' import GdcmWriteImageNodeResult from './gdcm-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function gdcmWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'gdcm-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'gdcm-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/gdcm-write-image.ts b/packages/image-io/typescript/src/gdcm-write-image.ts index 1259a77ce..ffaa9ecd8 100644 --- a/packages/image-io/typescript/src/gdcm-write-image.ts +++ b/packages/image-io/typescript/src/gdcm-write-image.ts @@ -13,7 +13,6 @@ import { import GdcmWriteImageOptions from './gdcm-write-image-options.js' import GdcmWriteImageResult from './gdcm-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function gdcmWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: GdcmWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/ge-adw-read-image-node.ts b/packages/image-io/typescript/src/ge-adw-read-image-node.ts index 49cf0d5fa..14cce2264 100644 --- a/packages/image-io/typescript/src/ge-adw-read-image-node.ts +++ b/packages/image-io/typescript/src/ge-adw-read-image-node.ts @@ -12,7 +12,6 @@ import { import GeAdwReadImageOptions from './ge-adw-read-image-options.js' import GeAdwReadImageNodeResult from './ge-adw-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function geAdwReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'ge-adw-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'ge-adw-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/ge-adw-read-image.ts b/packages/image-io/typescript/src/ge-adw-read-image.ts index c892a4397..f6c56602a 100644 --- a/packages/image-io/typescript/src/ge-adw-read-image.ts +++ b/packages/image-io/typescript/src/ge-adw-read-image.ts @@ -13,7 +13,6 @@ import { import GeAdwReadImageOptions from './ge-adw-read-image-options.js' import GeAdwReadImageResult from './ge-adw-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function geAdwReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: GeAdwReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/ge-adw-write-image-node.ts b/packages/image-io/typescript/src/ge-adw-write-image-node.ts index 77dc9a250..536174a03 100644 --- a/packages/image-io/typescript/src/ge-adw-write-image-node.ts +++ b/packages/image-io/typescript/src/ge-adw-write-image-node.ts @@ -12,7 +12,6 @@ import { import GeAdwWriteImageOptions from './ge-adw-write-image-options.js' import GeAdwWriteImageNodeResult from './ge-adw-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function geAdwWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'ge-adw-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'ge-adw-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/ge-adw-write-image.ts b/packages/image-io/typescript/src/ge-adw-write-image.ts index 5012e75e6..92e0d19b2 100644 --- a/packages/image-io/typescript/src/ge-adw-write-image.ts +++ b/packages/image-io/typescript/src/ge-adw-write-image.ts @@ -13,7 +13,6 @@ import { import GeAdwWriteImageOptions from './ge-adw-write-image-options.js' import GeAdwWriteImageResult from './ge-adw-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function geAdwWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: GeAdwWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/ge4-read-image-node.ts b/packages/image-io/typescript/src/ge4-read-image-node.ts index ac7c5b75b..442c27bcf 100644 --- a/packages/image-io/typescript/src/ge4-read-image-node.ts +++ b/packages/image-io/typescript/src/ge4-read-image-node.ts @@ -12,7 +12,6 @@ import { import Ge4ReadImageOptions from './ge4-read-image-options.js' import Ge4ReadImageNodeResult from './ge4-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function ge4ReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'ge4-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'ge4-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/ge4-read-image.ts b/packages/image-io/typescript/src/ge4-read-image.ts index 7c6b0a985..c7292dd57 100644 --- a/packages/image-io/typescript/src/ge4-read-image.ts +++ b/packages/image-io/typescript/src/ge4-read-image.ts @@ -13,7 +13,6 @@ import { import Ge4ReadImageOptions from './ge4-read-image-options.js' import Ge4ReadImageResult from './ge4-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function ge4ReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: Ge4ReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/ge4-write-image-node.ts b/packages/image-io/typescript/src/ge4-write-image-node.ts index 01e1cd308..0d9c82b54 100644 --- a/packages/image-io/typescript/src/ge4-write-image-node.ts +++ b/packages/image-io/typescript/src/ge4-write-image-node.ts @@ -12,7 +12,6 @@ import { import Ge4WriteImageOptions from './ge4-write-image-options.js' import Ge4WriteImageNodeResult from './ge4-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function ge4WriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'ge4-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'ge4-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/ge4-write-image.ts b/packages/image-io/typescript/src/ge4-write-image.ts index a9b49f9f6..6ea594d6c 100644 --- a/packages/image-io/typescript/src/ge4-write-image.ts +++ b/packages/image-io/typescript/src/ge4-write-image.ts @@ -13,7 +13,6 @@ import { import Ge4WriteImageOptions from './ge4-write-image-options.js' import Ge4WriteImageResult from './ge4-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function ge4WriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: Ge4WriteImageOptions = {} diff --git a/packages/image-io/typescript/src/ge5-read-image-node.ts b/packages/image-io/typescript/src/ge5-read-image-node.ts index 515fa3d82..73fe729f1 100644 --- a/packages/image-io/typescript/src/ge5-read-image-node.ts +++ b/packages/image-io/typescript/src/ge5-read-image-node.ts @@ -12,7 +12,6 @@ import { import Ge5ReadImageOptions from './ge5-read-image-options.js' import Ge5ReadImageNodeResult from './ge5-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function ge5ReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'ge5-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'ge5-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/ge5-read-image.ts b/packages/image-io/typescript/src/ge5-read-image.ts index b1c0b295a..df8f371ba 100644 --- a/packages/image-io/typescript/src/ge5-read-image.ts +++ b/packages/image-io/typescript/src/ge5-read-image.ts @@ -13,7 +13,6 @@ import { import Ge5ReadImageOptions from './ge5-read-image-options.js' import Ge5ReadImageResult from './ge5-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function ge5ReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: Ge5ReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/ge5-write-image-node.ts b/packages/image-io/typescript/src/ge5-write-image-node.ts index e4fb8d3f9..8babd9972 100644 --- a/packages/image-io/typescript/src/ge5-write-image-node.ts +++ b/packages/image-io/typescript/src/ge5-write-image-node.ts @@ -12,7 +12,6 @@ import { import Ge5WriteImageOptions from './ge5-write-image-options.js' import Ge5WriteImageNodeResult from './ge5-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function ge5WriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'ge5-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'ge5-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/ge5-write-image.ts b/packages/image-io/typescript/src/ge5-write-image.ts index 0188d9dcb..58696b8e0 100644 --- a/packages/image-io/typescript/src/ge5-write-image.ts +++ b/packages/image-io/typescript/src/ge5-write-image.ts @@ -13,7 +13,6 @@ import { import Ge5WriteImageOptions from './ge5-write-image-options.js' import Ge5WriteImageResult from './ge5-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function ge5WriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: Ge5WriteImageOptions = {} diff --git a/packages/image-io/typescript/src/gipl-read-image-node.ts b/packages/image-io/typescript/src/gipl-read-image-node.ts index 9b5c9727f..4df08c24c 100644 --- a/packages/image-io/typescript/src/gipl-read-image-node.ts +++ b/packages/image-io/typescript/src/gipl-read-image-node.ts @@ -12,7 +12,6 @@ import { import GiplReadImageOptions from './gipl-read-image-options.js' import GiplReadImageNodeResult from './gipl-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function giplReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'gipl-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'gipl-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/gipl-read-image.ts b/packages/image-io/typescript/src/gipl-read-image.ts index 499f98860..cfd506c90 100644 --- a/packages/image-io/typescript/src/gipl-read-image.ts +++ b/packages/image-io/typescript/src/gipl-read-image.ts @@ -13,7 +13,6 @@ import { import GiplReadImageOptions from './gipl-read-image-options.js' import GiplReadImageResult from './gipl-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function giplReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: GiplReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/gipl-write-image-node.ts b/packages/image-io/typescript/src/gipl-write-image-node.ts index 248d54096..6fcaa1338 100644 --- a/packages/image-io/typescript/src/gipl-write-image-node.ts +++ b/packages/image-io/typescript/src/gipl-write-image-node.ts @@ -12,7 +12,6 @@ import { import GiplWriteImageOptions from './gipl-write-image-options.js' import GiplWriteImageNodeResult from './gipl-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function giplWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'gipl-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'gipl-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/gipl-write-image.ts b/packages/image-io/typescript/src/gipl-write-image.ts index 5c41bbd22..a8a97db38 100644 --- a/packages/image-io/typescript/src/gipl-write-image.ts +++ b/packages/image-io/typescript/src/gipl-write-image.ts @@ -13,7 +13,6 @@ import { import GiplWriteImageOptions from './gipl-write-image-options.js' import GiplWriteImageResult from './gipl-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function giplWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: GiplWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/hdf5-read-image-node.ts b/packages/image-io/typescript/src/hdf5-read-image-node.ts index 6c781b8e4..95e136f34 100644 --- a/packages/image-io/typescript/src/hdf5-read-image-node.ts +++ b/packages/image-io/typescript/src/hdf5-read-image-node.ts @@ -12,7 +12,6 @@ import { import Hdf5ReadImageOptions from './hdf5-read-image-options.js' import Hdf5ReadImageNodeResult from './hdf5-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function hdf5ReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'hdf5-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'hdf5-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/hdf5-read-image.ts b/packages/image-io/typescript/src/hdf5-read-image.ts index 2f563d69d..7124ca66b 100644 --- a/packages/image-io/typescript/src/hdf5-read-image.ts +++ b/packages/image-io/typescript/src/hdf5-read-image.ts @@ -13,7 +13,6 @@ import { import Hdf5ReadImageOptions from './hdf5-read-image-options.js' import Hdf5ReadImageResult from './hdf5-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function hdf5ReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: Hdf5ReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/hdf5-write-image-node.ts b/packages/image-io/typescript/src/hdf5-write-image-node.ts index 5228d231a..884332183 100644 --- a/packages/image-io/typescript/src/hdf5-write-image-node.ts +++ b/packages/image-io/typescript/src/hdf5-write-image-node.ts @@ -12,7 +12,6 @@ import { import Hdf5WriteImageOptions from './hdf5-write-image-options.js' import Hdf5WriteImageNodeResult from './hdf5-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function hdf5WriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'hdf5-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'hdf5-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/hdf5-write-image.ts b/packages/image-io/typescript/src/hdf5-write-image.ts index 8ef0fa145..4e2a810f6 100644 --- a/packages/image-io/typescript/src/hdf5-write-image.ts +++ b/packages/image-io/typescript/src/hdf5-write-image.ts @@ -13,7 +13,6 @@ import { import Hdf5WriteImageOptions from './hdf5-write-image-options.js' import Hdf5WriteImageResult from './hdf5-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function hdf5WriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: Hdf5WriteImageOptions = {} diff --git a/packages/image-io/typescript/src/itkConfig.js b/packages/image-io/typescript/src/itkConfig.js deleted file mode 100644 index be9beaf3f..000000000 --- a/packages/image-io/typescript/src/itkConfig.js +++ /dev/null @@ -1,11 +0,0 @@ -import version from 'itk-wasm' - -const itkConfig = { - // Use the worker bundled by vite or webpack - pipelineWorkerUrl: null, - imageIOUrl: `https://cdn.jsdelivr.net/npm/itk-image-io@${version}`, - meshIOUrl: `https://cdn.jsdelivr.net/npm/itk-mesh-io@${version}`, - pipelinesUrl: '/pipelines' -} - -export default itkConfig diff --git a/packages/image-io/typescript/src/jpeg-read-image-node.ts b/packages/image-io/typescript/src/jpeg-read-image-node.ts index ec5d44d49..1fc8c564d 100644 --- a/packages/image-io/typescript/src/jpeg-read-image-node.ts +++ b/packages/image-io/typescript/src/jpeg-read-image-node.ts @@ -12,7 +12,6 @@ import { import JpegReadImageOptions from './jpeg-read-image-options.js' import JpegReadImageNodeResult from './jpeg-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function jpegReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'jpeg-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'jpeg-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/jpeg-read-image.ts b/packages/image-io/typescript/src/jpeg-read-image.ts index ed917708d..45b775677 100644 --- a/packages/image-io/typescript/src/jpeg-read-image.ts +++ b/packages/image-io/typescript/src/jpeg-read-image.ts @@ -13,7 +13,6 @@ import { import JpegReadImageOptions from './jpeg-read-image-options.js' import JpegReadImageResult from './jpeg-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function jpegReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: JpegReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/jpeg-write-image-node.ts b/packages/image-io/typescript/src/jpeg-write-image-node.ts index 546f45a99..d9bf7cc5f 100644 --- a/packages/image-io/typescript/src/jpeg-write-image-node.ts +++ b/packages/image-io/typescript/src/jpeg-write-image-node.ts @@ -12,7 +12,6 @@ import { import JpegWriteImageOptions from './jpeg-write-image-options.js' import JpegWriteImageNodeResult from './jpeg-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function jpegWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'jpeg-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'jpeg-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/jpeg-write-image.ts b/packages/image-io/typescript/src/jpeg-write-image.ts index de607d954..c512cbbf2 100644 --- a/packages/image-io/typescript/src/jpeg-write-image.ts +++ b/packages/image-io/typescript/src/jpeg-write-image.ts @@ -13,7 +13,6 @@ import { import JpegWriteImageOptions from './jpeg-write-image-options.js' import JpegWriteImageResult from './jpeg-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function jpegWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: JpegWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/lsm-read-image-node.ts b/packages/image-io/typescript/src/lsm-read-image-node.ts index 13c1d5932..409e6c6a1 100644 --- a/packages/image-io/typescript/src/lsm-read-image-node.ts +++ b/packages/image-io/typescript/src/lsm-read-image-node.ts @@ -12,7 +12,6 @@ import { import LsmReadImageOptions from './lsm-read-image-options.js' import LsmReadImageNodeResult from './lsm-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function lsmReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'lsm-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'lsm-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/lsm-read-image.ts b/packages/image-io/typescript/src/lsm-read-image.ts index 9493aa57e..865585b4c 100644 --- a/packages/image-io/typescript/src/lsm-read-image.ts +++ b/packages/image-io/typescript/src/lsm-read-image.ts @@ -13,7 +13,6 @@ import { import LsmReadImageOptions from './lsm-read-image-options.js' import LsmReadImageResult from './lsm-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function lsmReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: LsmReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/lsm-write-image-node.ts b/packages/image-io/typescript/src/lsm-write-image-node.ts index 4f7a7e276..96be6baa5 100644 --- a/packages/image-io/typescript/src/lsm-write-image-node.ts +++ b/packages/image-io/typescript/src/lsm-write-image-node.ts @@ -12,7 +12,6 @@ import { import LsmWriteImageOptions from './lsm-write-image-options.js' import LsmWriteImageNodeResult from './lsm-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function lsmWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'lsm-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'lsm-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/lsm-write-image.ts b/packages/image-io/typescript/src/lsm-write-image.ts index b80040875..9cd2b9470 100644 --- a/packages/image-io/typescript/src/lsm-write-image.ts +++ b/packages/image-io/typescript/src/lsm-write-image.ts @@ -13,7 +13,6 @@ import { import LsmWriteImageOptions from './lsm-write-image-options.js' import LsmWriteImageResult from './lsm-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function lsmWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: LsmWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/meta-read-image-node.ts b/packages/image-io/typescript/src/meta-read-image-node.ts index e3b544832..284e694c4 100644 --- a/packages/image-io/typescript/src/meta-read-image-node.ts +++ b/packages/image-io/typescript/src/meta-read-image-node.ts @@ -12,7 +12,6 @@ import { import MetaReadImageOptions from './meta-read-image-options.js' import MetaReadImageNodeResult from './meta-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function metaReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'meta-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'meta-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/meta-read-image.ts b/packages/image-io/typescript/src/meta-read-image.ts index 997f3560b..d500273e3 100644 --- a/packages/image-io/typescript/src/meta-read-image.ts +++ b/packages/image-io/typescript/src/meta-read-image.ts @@ -13,7 +13,6 @@ import { import MetaReadImageOptions from './meta-read-image-options.js' import MetaReadImageResult from './meta-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function metaReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: MetaReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/meta-write-image-node.ts b/packages/image-io/typescript/src/meta-write-image-node.ts index 7e265ee11..ce7f42824 100644 --- a/packages/image-io/typescript/src/meta-write-image-node.ts +++ b/packages/image-io/typescript/src/meta-write-image-node.ts @@ -12,7 +12,6 @@ import { import MetaWriteImageOptions from './meta-write-image-options.js' import MetaWriteImageNodeResult from './meta-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function metaWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'meta-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'meta-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/meta-write-image.ts b/packages/image-io/typescript/src/meta-write-image.ts index 2896bc969..14572cff7 100644 --- a/packages/image-io/typescript/src/meta-write-image.ts +++ b/packages/image-io/typescript/src/meta-write-image.ts @@ -13,7 +13,6 @@ import { import MetaWriteImageOptions from './meta-write-image-options.js' import MetaWriteImageResult from './meta-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function metaWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: MetaWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/mgh-read-image-node.ts b/packages/image-io/typescript/src/mgh-read-image-node.ts index e54b31eef..3078c07cf 100644 --- a/packages/image-io/typescript/src/mgh-read-image-node.ts +++ b/packages/image-io/typescript/src/mgh-read-image-node.ts @@ -12,7 +12,6 @@ import { import MghReadImageOptions from './mgh-read-image-options.js' import MghReadImageNodeResult from './mgh-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function mghReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'mgh-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'mgh-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/mgh-read-image.ts b/packages/image-io/typescript/src/mgh-read-image.ts index 3424fd816..f7a8548de 100644 --- a/packages/image-io/typescript/src/mgh-read-image.ts +++ b/packages/image-io/typescript/src/mgh-read-image.ts @@ -13,7 +13,6 @@ import { import MghReadImageOptions from './mgh-read-image-options.js' import MghReadImageResult from './mgh-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function mghReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: MghReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/mgh-write-image-node.ts b/packages/image-io/typescript/src/mgh-write-image-node.ts index a3c9f916c..0294ab91e 100644 --- a/packages/image-io/typescript/src/mgh-write-image-node.ts +++ b/packages/image-io/typescript/src/mgh-write-image-node.ts @@ -12,7 +12,6 @@ import { import MghWriteImageOptions from './mgh-write-image-options.js' import MghWriteImageNodeResult from './mgh-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function mghWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'mgh-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'mgh-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/mgh-write-image.ts b/packages/image-io/typescript/src/mgh-write-image.ts index ded3e724c..99d745d1d 100644 --- a/packages/image-io/typescript/src/mgh-write-image.ts +++ b/packages/image-io/typescript/src/mgh-write-image.ts @@ -13,7 +13,6 @@ import { import MghWriteImageOptions from './mgh-write-image-options.js' import MghWriteImageResult from './mgh-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function mghWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: MghWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/minc-read-image-node.ts b/packages/image-io/typescript/src/minc-read-image-node.ts index cfbf0e4f5..83c070f26 100644 --- a/packages/image-io/typescript/src/minc-read-image-node.ts +++ b/packages/image-io/typescript/src/minc-read-image-node.ts @@ -12,7 +12,6 @@ import { import MincReadImageOptions from './minc-read-image-options.js' import MincReadImageNodeResult from './minc-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function mincReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'minc-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'minc-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/minc-read-image.ts b/packages/image-io/typescript/src/minc-read-image.ts index b13d3997f..70fa4c7bd 100644 --- a/packages/image-io/typescript/src/minc-read-image.ts +++ b/packages/image-io/typescript/src/minc-read-image.ts @@ -13,7 +13,6 @@ import { import MincReadImageOptions from './minc-read-image-options.js' import MincReadImageResult from './minc-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function mincReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: MincReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/minc-write-image-node.ts b/packages/image-io/typescript/src/minc-write-image-node.ts index 716725ddd..53b1e8a40 100644 --- a/packages/image-io/typescript/src/minc-write-image-node.ts +++ b/packages/image-io/typescript/src/minc-write-image-node.ts @@ -12,7 +12,6 @@ import { import MincWriteImageOptions from './minc-write-image-options.js' import MincWriteImageNodeResult from './minc-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function mincWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'minc-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'minc-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/minc-write-image.ts b/packages/image-io/typescript/src/minc-write-image.ts index b4cc378f5..db61de6a6 100644 --- a/packages/image-io/typescript/src/minc-write-image.ts +++ b/packages/image-io/typescript/src/minc-write-image.ts @@ -13,7 +13,6 @@ import { import MincWriteImageOptions from './minc-write-image-options.js' import MincWriteImageResult from './minc-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function mincWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: MincWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/mrc-read-image-node.ts b/packages/image-io/typescript/src/mrc-read-image-node.ts index f58d7494e..46fbb20a1 100644 --- a/packages/image-io/typescript/src/mrc-read-image-node.ts +++ b/packages/image-io/typescript/src/mrc-read-image-node.ts @@ -12,7 +12,6 @@ import { import MrcReadImageOptions from './mrc-read-image-options.js' import MrcReadImageNodeResult from './mrc-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function mrcReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'mrc-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'mrc-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/mrc-read-image.ts b/packages/image-io/typescript/src/mrc-read-image.ts index 172abccdc..055657f86 100644 --- a/packages/image-io/typescript/src/mrc-read-image.ts +++ b/packages/image-io/typescript/src/mrc-read-image.ts @@ -13,7 +13,6 @@ import { import MrcReadImageOptions from './mrc-read-image-options.js' import MrcReadImageResult from './mrc-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function mrcReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: MrcReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/mrc-write-image-node.ts b/packages/image-io/typescript/src/mrc-write-image-node.ts index f90fb6462..5b7191b3d 100644 --- a/packages/image-io/typescript/src/mrc-write-image-node.ts +++ b/packages/image-io/typescript/src/mrc-write-image-node.ts @@ -12,7 +12,6 @@ import { import MrcWriteImageOptions from './mrc-write-image-options.js' import MrcWriteImageNodeResult from './mrc-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function mrcWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'mrc-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'mrc-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/mrc-write-image.ts b/packages/image-io/typescript/src/mrc-write-image.ts index da2cdba21..62b010f5f 100644 --- a/packages/image-io/typescript/src/mrc-write-image.ts +++ b/packages/image-io/typescript/src/mrc-write-image.ts @@ -13,7 +13,6 @@ import { import MrcWriteImageOptions from './mrc-write-image-options.js' import MrcWriteImageResult from './mrc-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function mrcWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: MrcWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/nifti-read-image-node.ts b/packages/image-io/typescript/src/nifti-read-image-node.ts index 9beb6225f..2e7d0238d 100644 --- a/packages/image-io/typescript/src/nifti-read-image-node.ts +++ b/packages/image-io/typescript/src/nifti-read-image-node.ts @@ -12,7 +12,6 @@ import { import NiftiReadImageOptions from './nifti-read-image-options.js' import NiftiReadImageNodeResult from './nifti-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function niftiReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'nifti-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'nifti-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/nifti-read-image.ts b/packages/image-io/typescript/src/nifti-read-image.ts index 28f68743c..07cce876d 100644 --- a/packages/image-io/typescript/src/nifti-read-image.ts +++ b/packages/image-io/typescript/src/nifti-read-image.ts @@ -13,7 +13,6 @@ import { import NiftiReadImageOptions from './nifti-read-image-options.js' import NiftiReadImageResult from './nifti-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function niftiReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: NiftiReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/nifti-write-image-node.ts b/packages/image-io/typescript/src/nifti-write-image-node.ts index 793fc64b7..29b11d3eb 100644 --- a/packages/image-io/typescript/src/nifti-write-image-node.ts +++ b/packages/image-io/typescript/src/nifti-write-image-node.ts @@ -12,7 +12,6 @@ import { import NiftiWriteImageOptions from './nifti-write-image-options.js' import NiftiWriteImageNodeResult from './nifti-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function niftiWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'nifti-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'nifti-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/nifti-write-image.ts b/packages/image-io/typescript/src/nifti-write-image.ts index 242c3879c..c2637f6db 100644 --- a/packages/image-io/typescript/src/nifti-write-image.ts +++ b/packages/image-io/typescript/src/nifti-write-image.ts @@ -13,7 +13,6 @@ import { import NiftiWriteImageOptions from './nifti-write-image-options.js' import NiftiWriteImageResult from './nifti-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function niftiWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: NiftiWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/nrrd-read-image-node.ts b/packages/image-io/typescript/src/nrrd-read-image-node.ts index 8fbbc174e..992710796 100644 --- a/packages/image-io/typescript/src/nrrd-read-image-node.ts +++ b/packages/image-io/typescript/src/nrrd-read-image-node.ts @@ -12,7 +12,6 @@ import { import NrrdReadImageOptions from './nrrd-read-image-options.js' import NrrdReadImageNodeResult from './nrrd-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function nrrdReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'nrrd-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'nrrd-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/nrrd-read-image.ts b/packages/image-io/typescript/src/nrrd-read-image.ts index e8e0fc265..041ee37bc 100644 --- a/packages/image-io/typescript/src/nrrd-read-image.ts +++ b/packages/image-io/typescript/src/nrrd-read-image.ts @@ -13,7 +13,6 @@ import { import NrrdReadImageOptions from './nrrd-read-image-options.js' import NrrdReadImageResult from './nrrd-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function nrrdReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: NrrdReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/nrrd-write-image-node.ts b/packages/image-io/typescript/src/nrrd-write-image-node.ts index 2c4758285..c9fb86c05 100644 --- a/packages/image-io/typescript/src/nrrd-write-image-node.ts +++ b/packages/image-io/typescript/src/nrrd-write-image-node.ts @@ -12,7 +12,6 @@ import { import NrrdWriteImageOptions from './nrrd-write-image-options.js' import NrrdWriteImageNodeResult from './nrrd-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function nrrdWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'nrrd-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'nrrd-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/nrrd-write-image.ts b/packages/image-io/typescript/src/nrrd-write-image.ts index 5416d2e59..61d605442 100644 --- a/packages/image-io/typescript/src/nrrd-write-image.ts +++ b/packages/image-io/typescript/src/nrrd-write-image.ts @@ -13,7 +13,6 @@ import { import NrrdWriteImageOptions from './nrrd-write-image-options.js' import NrrdWriteImageResult from './nrrd-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function nrrdWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: NrrdWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/package.json b/packages/image-io/typescript/src/package.json new file mode 120000 index 000000000..4e26811d4 --- /dev/null +++ b/packages/image-io/typescript/src/package.json @@ -0,0 +1 @@ +../package.json \ No newline at end of file diff --git a/packages/image-io/typescript/src/pipeline-worker-url.ts b/packages/image-io/typescript/src/pipeline-worker-url.ts index 1a697038e..39118ba4a 100644 --- a/packages/image-io/typescript/src/pipeline-worker-url.ts +++ b/packages/image-io/typescript/src/pipeline-worker-url.ts @@ -1,8 +1,8 @@ import { getPipelineWorkerUrl as itkWasmGetPipelineWorkerUrl } from 'itk-wasm' -import packageJson from '../package.json' let pipelineWorkerUrl: string | URL | null | undefined -const defaultPipelineWorkerUrl = `https://cdn.jsdelivr.net/npm/@itk-wasm/image-io@${packageJson.version}/dist/web-workers/pipeline.worker.js` +// Use the version shipped with an app's bundler +const defaultPipelineWorkerUrl = null export function setPipelineWorkerUrl (workerUrl: string | URL | null): void { pipelineWorkerUrl = workerUrl diff --git a/packages/image-io/typescript/src/pipelines-base-url.ts b/packages/image-io/typescript/src/pipelines-base-url.ts index cb258695e..16f82b6e3 100644 --- a/packages/image-io/typescript/src/pipelines-base-url.ts +++ b/packages/image-io/typescript/src/pipelines-base-url.ts @@ -1,5 +1,5 @@ import { getPipelinesBaseUrl as itkWasmGetPipelinesBaseUrl } from 'itk-wasm' -import packageJson from '../package.json' +import packageJson from './package.json' let pipelinesBaseUrl: string | URL | undefined let defaultPipelinesBaseUrl: string | URL = `https://cdn.jsdelivr.net/npm/@itk-wasm/image-io@${packageJson.version}/dist/pipelines` diff --git a/packages/image-io/typescript/src/png-read-image-node.ts b/packages/image-io/typescript/src/png-read-image-node.ts index e622252dd..61bd0777c 100644 --- a/packages/image-io/typescript/src/png-read-image-node.ts +++ b/packages/image-io/typescript/src/png-read-image-node.ts @@ -12,7 +12,6 @@ import { import PngReadImageOptions from './png-read-image-options.js' import PngReadImageNodeResult from './png-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function pngReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'png-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'png-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/png-read-image.ts b/packages/image-io/typescript/src/png-read-image.ts index 2ecd998e8..c6a607871 100644 --- a/packages/image-io/typescript/src/png-read-image.ts +++ b/packages/image-io/typescript/src/png-read-image.ts @@ -13,7 +13,6 @@ import { import PngReadImageOptions from './png-read-image-options.js' import PngReadImageResult from './png-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function pngReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: PngReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/png-write-image-node.ts b/packages/image-io/typescript/src/png-write-image-node.ts index 9dcc1e00a..06d2a1c52 100644 --- a/packages/image-io/typescript/src/png-write-image-node.ts +++ b/packages/image-io/typescript/src/png-write-image-node.ts @@ -12,7 +12,6 @@ import { import PngWriteImageOptions from './png-write-image-options.js' import PngWriteImageNodeResult from './png-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function pngWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'png-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'png-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/png-write-image.ts b/packages/image-io/typescript/src/png-write-image.ts index 54654fe06..7cbbc201b 100644 --- a/packages/image-io/typescript/src/png-write-image.ts +++ b/packages/image-io/typescript/src/png-write-image.ts @@ -13,7 +13,6 @@ import { import PngWriteImageOptions from './png-write-image-options.js' import PngWriteImageResult from './png-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function pngWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: PngWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/scanco-read-image-node.ts b/packages/image-io/typescript/src/scanco-read-image-node.ts index 4474feab8..199c989ac 100644 --- a/packages/image-io/typescript/src/scanco-read-image-node.ts +++ b/packages/image-io/typescript/src/scanco-read-image-node.ts @@ -12,7 +12,6 @@ import { import ScancoReadImageOptions from './scanco-read-image-options.js' import ScancoReadImageNodeResult from './scanco-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function scancoReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'scanco-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'scanco-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/scanco-read-image.ts b/packages/image-io/typescript/src/scanco-read-image.ts index ba6255dda..4d8169cee 100644 --- a/packages/image-io/typescript/src/scanco-read-image.ts +++ b/packages/image-io/typescript/src/scanco-read-image.ts @@ -13,7 +13,6 @@ import { import ScancoReadImageOptions from './scanco-read-image-options.js' import ScancoReadImageResult from './scanco-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function scancoReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: ScancoReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/scanco-write-image-node.ts b/packages/image-io/typescript/src/scanco-write-image-node.ts index b26e9e03d..3d67538f9 100644 --- a/packages/image-io/typescript/src/scanco-write-image-node.ts +++ b/packages/image-io/typescript/src/scanco-write-image-node.ts @@ -12,7 +12,6 @@ import { import ScancoWriteImageOptions from './scanco-write-image-options.js' import ScancoWriteImageNodeResult from './scanco-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function scancoWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'scanco-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'scanco-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/scanco-write-image.ts b/packages/image-io/typescript/src/scanco-write-image.ts index 2830881ca..dcbd0b59e 100644 --- a/packages/image-io/typescript/src/scanco-write-image.ts +++ b/packages/image-io/typescript/src/scanco-write-image.ts @@ -13,7 +13,6 @@ import { import ScancoWriteImageOptions from './scanco-write-image-options.js' import ScancoWriteImageResult from './scanco-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function scancoWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: ScancoWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/tiff-read-image-node.ts b/packages/image-io/typescript/src/tiff-read-image-node.ts index 201e6d178..fa25e7495 100644 --- a/packages/image-io/typescript/src/tiff-read-image-node.ts +++ b/packages/image-io/typescript/src/tiff-read-image-node.ts @@ -12,7 +12,6 @@ import { import TiffReadImageOptions from './tiff-read-image-options.js' import TiffReadImageNodeResult from './tiff-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function tiffReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'tiff-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'tiff-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/tiff-read-image.ts b/packages/image-io/typescript/src/tiff-read-image.ts index f06ea20aa..af3e21de8 100644 --- a/packages/image-io/typescript/src/tiff-read-image.ts +++ b/packages/image-io/typescript/src/tiff-read-image.ts @@ -13,7 +13,6 @@ import { import TiffReadImageOptions from './tiff-read-image-options.js' import TiffReadImageResult from './tiff-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function tiffReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: TiffReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/tiff-write-image-node.ts b/packages/image-io/typescript/src/tiff-write-image-node.ts index 0ebdc8071..aeb103c63 100644 --- a/packages/image-io/typescript/src/tiff-write-image-node.ts +++ b/packages/image-io/typescript/src/tiff-write-image-node.ts @@ -12,7 +12,6 @@ import { import TiffWriteImageOptions from './tiff-write-image-options.js' import TiffWriteImageNodeResult from './tiff-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function tiffWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'tiff-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'tiff-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/tiff-write-image.ts b/packages/image-io/typescript/src/tiff-write-image.ts index 5cf8922f7..99e43b420 100644 --- a/packages/image-io/typescript/src/tiff-write-image.ts +++ b/packages/image-io/typescript/src/tiff-write-image.ts @@ -13,7 +13,6 @@ import { import TiffWriteImageOptions from './tiff-write-image-options.js' import TiffWriteImageResult from './tiff-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function tiffWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: TiffWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/vtk-read-image-node.ts b/packages/image-io/typescript/src/vtk-read-image-node.ts index 73bb349b4..b9c174ee5 100644 --- a/packages/image-io/typescript/src/vtk-read-image-node.ts +++ b/packages/image-io/typescript/src/vtk-read-image-node.ts @@ -12,7 +12,6 @@ import { import VtkReadImageOptions from './vtk-read-image-options.js' import VtkReadImageNodeResult from './vtk-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function vtkReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'vtk-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'vtk-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/vtk-read-image.ts b/packages/image-io/typescript/src/vtk-read-image.ts index 795570241..468e86a35 100644 --- a/packages/image-io/typescript/src/vtk-read-image.ts +++ b/packages/image-io/typescript/src/vtk-read-image.ts @@ -13,7 +13,6 @@ import { import VtkReadImageOptions from './vtk-read-image-options.js' import VtkReadImageResult from './vtk-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function vtkReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: VtkReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/vtk-write-image-node.ts b/packages/image-io/typescript/src/vtk-write-image-node.ts index c89d142ad..5ff86d9ac 100644 --- a/packages/image-io/typescript/src/vtk-write-image-node.ts +++ b/packages/image-io/typescript/src/vtk-write-image-node.ts @@ -12,7 +12,6 @@ import { import VtkWriteImageOptions from './vtk-write-image-options.js' import VtkWriteImageNodeResult from './vtk-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function vtkWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'vtk-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'vtk-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/vtk-write-image.ts b/packages/image-io/typescript/src/vtk-write-image.ts index 4a179c471..23990e885 100644 --- a/packages/image-io/typescript/src/vtk-write-image.ts +++ b/packages/image-io/typescript/src/vtk-write-image.ts @@ -13,7 +13,6 @@ import { import VtkWriteImageOptions from './vtk-write-image-options.js' import VtkWriteImageResult from './vtk-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function vtkWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: VtkWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/wasm-read-image-node.ts b/packages/image-io/typescript/src/wasm-read-image-node.ts index a16cf49e2..1a3efeb65 100644 --- a/packages/image-io/typescript/src/wasm-read-image-node.ts +++ b/packages/image-io/typescript/src/wasm-read-image-node.ts @@ -12,7 +12,6 @@ import { import WasmReadImageOptions from './wasm-read-image-options.js' import WasmReadImageNodeResult from './wasm-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function wasmReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'wasm-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'wasm-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/wasm-read-image.ts b/packages/image-io/typescript/src/wasm-read-image.ts index 0e57b01be..fdea47ac2 100644 --- a/packages/image-io/typescript/src/wasm-read-image.ts +++ b/packages/image-io/typescript/src/wasm-read-image.ts @@ -13,7 +13,6 @@ import { import WasmReadImageOptions from './wasm-read-image-options.js' import WasmReadImageResult from './wasm-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function wasmReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: WasmReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/wasm-write-image-node.ts b/packages/image-io/typescript/src/wasm-write-image-node.ts index 2c6b0e039..34bac25ee 100644 --- a/packages/image-io/typescript/src/wasm-write-image-node.ts +++ b/packages/image-io/typescript/src/wasm-write-image-node.ts @@ -12,7 +12,6 @@ import { import WasmWriteImageOptions from './wasm-write-image-options.js' import WasmWriteImageNodeResult from './wasm-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function wasmWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'wasm-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'wasm-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/wasm-write-image.ts b/packages/image-io/typescript/src/wasm-write-image.ts index 7d7674cee..926171ded 100644 --- a/packages/image-io/typescript/src/wasm-write-image.ts +++ b/packages/image-io/typescript/src/wasm-write-image.ts @@ -13,7 +13,6 @@ import { import WasmWriteImageOptions from './wasm-write-image-options.js' import WasmWriteImageResult from './wasm-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function wasmWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: WasmWriteImageOptions = {} diff --git a/packages/image-io/typescript/src/wasm-zstd-read-image-node.ts b/packages/image-io/typescript/src/wasm-zstd-read-image-node.ts index 7097b513e..7d5182a46 100644 --- a/packages/image-io/typescript/src/wasm-zstd-read-image-node.ts +++ b/packages/image-io/typescript/src/wasm-zstd-read-image-node.ts @@ -12,7 +12,6 @@ import { import WasmZstdReadImageOptions from './wasm-zstd-read-image-options.js' import WasmZstdReadImageNodeResult from './wasm-zstd-read-image-node-result.js' - import path from 'path' /** @@ -58,7 +57,7 @@ async function wasmZstdReadImageNode( options.informationOnly && args.push('--information-only') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'wasm-zstd-read-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'wasm-zstd-read-image') const { returnValue, diff --git a/packages/image-io/typescript/src/wasm-zstd-read-image.ts b/packages/image-io/typescript/src/wasm-zstd-read-image.ts index c15d4b20f..18e36a60e 100644 --- a/packages/image-io/typescript/src/wasm-zstd-read-image.ts +++ b/packages/image-io/typescript/src/wasm-zstd-read-image.ts @@ -13,7 +13,6 @@ import { import WasmZstdReadImageOptions from './wasm-zstd-read-image-options.js' import WasmZstdReadImageResult from './wasm-zstd-read-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -26,7 +25,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function wasmZstdReadImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: WasmZstdReadImageOptions = {} ) : Promise { diff --git a/packages/image-io/typescript/src/wasm-zstd-write-image-node.ts b/packages/image-io/typescript/src/wasm-zstd-write-image-node.ts index a36184c36..d8fa2b4a6 100644 --- a/packages/image-io/typescript/src/wasm-zstd-write-image-node.ts +++ b/packages/image-io/typescript/src/wasm-zstd-write-image-node.ts @@ -12,7 +12,6 @@ import { import WasmZstdWriteImageOptions from './wasm-zstd-write-image-options.js' import WasmZstdWriteImageNodeResult from './wasm-zstd-write-image-node-result.js' - import path from 'path' /** @@ -62,7 +61,7 @@ async function wasmZstdWriteImageNode( options.useCompression && args.push('--use-compression') } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'wasm-zstd-write-image') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'wasm-zstd-write-image') const { returnValue, diff --git a/packages/image-io/typescript/src/wasm-zstd-write-image.ts b/packages/image-io/typescript/src/wasm-zstd-write-image.ts index b1489b6f0..3b9a9fbd6 100644 --- a/packages/image-io/typescript/src/wasm-zstd-write-image.ts +++ b/packages/image-io/typescript/src/wasm-zstd-write-image.ts @@ -13,7 +13,6 @@ import { import WasmZstdWriteImageOptions from './wasm-zstd-write-image-options.js' import WasmZstdWriteImageResult from './wasm-zstd-write-image-result.js' - import { getPipelinesBaseUrl } from './pipelines-base-url.js' import { getPipelineWorkerUrl } from './pipeline-worker-url.js' @@ -27,7 +26,7 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function wasmZstdWriteImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, image: Image, serializedImage: string, options: WasmZstdWriteImageOptions = {} diff --git a/packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-controller.ts new file mode 100644 index 000000000..cba12be41 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-controller.ts @@ -0,0 +1,171 @@ +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import bioRadReadImageLoadSampleInputs, { usePreRun } from "./bio-rad-read-image-load-sample-inputs.js" + +class BioRadReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class BioRadReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new BioRadReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#bioRadReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#bioRadReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("bioRadReadImage-serialized-image-details") + details.innerHTML = `

${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#bioRadReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#bioRadReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#bioRadReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'bioRadReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'bioRadReadImage') { + params.set('functionName', 'bioRadReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'bioRadReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'bioRadReadImage') { + tabGroup.show('bioRadReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#bioRadReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("bioRadReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("bioRadReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("bioRadReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("bioRadReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('bioRadReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.bioRadReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const bioRadReadImageController = new BioRadReadImageController(bioRadReadImageLoadSampleInputs) + \ No newline at end of file diff --git a/packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..eb8aff3d9 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bio-rad-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function bioRadReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the bioRadReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#bioRadReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-controller.ts new file mode 100644 index 000000000..859a2a99e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-controller.ts @@ -0,0 +1,175 @@ +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import bioRadWriteImageLoadSampleInputs, { usePreRun } from "./bio-rad-write-image-load-sample-inputs.js" + +class BioRadWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class BioRadWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new BioRadWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#bioRadWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#bioRadWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("bioRadWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#bioRadWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#bioRadWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#bioRadWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#bioRadWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#bioRadWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'bioRadWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'bioRadWriteImage') { + params.set('functionName', 'bioRadWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'bioRadWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'bioRadWriteImage') { + tabGroup.show('bioRadWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#bioRadWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("bioRadWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("bioRadWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("bioRadWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("bioRadWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.bioRadWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const bioRadWriteImageController = new BioRadWriteImageController(bioRadWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..d6ba20cfc --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bio-rad-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function bioRadWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the bioRadWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#bioRadWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/bmp-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/bmp-read-image-controller.ts new file mode 100644 index 000000000..3eb7254a4 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bmp-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import bmpReadImageLoadSampleInputs, { usePreRun } from "./bmp-read-image-load-sample-inputs.js" + +class BmpReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class BmpReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new BmpReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#bmpReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#bmpReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("bmpReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#bmpReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#bmpReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#bmpReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'bmpReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'bmpReadImage') { + params.set('functionName', 'bmpReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'bmpReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'bmpReadImage') { + tabGroup.show('bmpReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#bmpReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("bmpReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("bmpReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("bmpReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("bmpReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('bmpReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.bmpReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const bmpReadImageController = new BmpReadImageController(bmpReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/bmp-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/bmp-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..bf38a1882 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bmp-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function bmpReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the bmpReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#bmpReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/bmp-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/bmp-write-image-controller.ts new file mode 100644 index 000000000..3854b4090 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bmp-write-image-controller.ts @@ -0,0 +1,175 @@ +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import bmpWriteImageLoadSampleInputs, { usePreRun } from "./bmp-write-image-load-sample-inputs.js" + +class BmpWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class BmpWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new BmpWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#bmpWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#bmpWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("bmpWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#bmpWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#bmpWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#bmpWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#bmpWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#bmpWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'bmpWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'bmpWriteImage') { + params.set('functionName', 'bmpWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'bmpWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'bmpWriteImage') { + tabGroup.show('bmpWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#bmpWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("bmpWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("bmpWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("bmpWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("bmpWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.bmpWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const bmpWriteImageController = new BmpWriteImageController(bmpWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/bmp-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/bmp-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..0d9d8e02c --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/bmp-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function bmpWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the bmpWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#bmpWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/fdf-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/fdf-read-image-controller.ts new file mode 100644 index 000000000..56de94919 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/fdf-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import fdfReadImageLoadSampleInputs, { usePreRun } from "./fdf-read-image-load-sample-inputs.js" + +class FdfReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class FdfReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new FdfReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#fdfReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#fdfReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("fdfReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#fdfReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#fdfReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#fdfReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'fdfReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'fdfReadImage') { + params.set('functionName', 'fdfReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'fdfReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'fdfReadImage') { + tabGroup.show('fdfReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#fdfReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("fdfReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("fdfReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("fdfReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("fdfReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('fdfReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.fdfReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const fdfReadImageController = new FdfReadImageController(fdfReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/fdf-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/fdf-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..85845b71a --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/fdf-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function fdfReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the fdfReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#fdfReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/fdf-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/fdf-write-image-controller.ts new file mode 100644 index 000000000..91bb09266 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/fdf-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import fdfWriteImageLoadSampleInputs, { usePreRun } from "./fdf-write-image-load-sample-inputs.js" + +class FdfWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class FdfWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new FdfWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#fdfWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#fdfWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("fdfWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#fdfWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#fdfWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#fdfWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#fdfWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#fdfWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'fdfWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'fdfWriteImage') { + params.set('functionName', 'fdfWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'fdfWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'fdfWriteImage') { + tabGroup.show('fdfWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#fdfWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("fdfWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("fdfWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("fdfWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("fdfWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.fdfWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const fdfWriteImageController = new FdfWriteImageController(fdfWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/fdf-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/fdf-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..5ac09dd37 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/fdf-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function fdfWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the fdfWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#fdfWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-controller.ts new file mode 100644 index 000000000..281b8bdb5 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import gdcmReadImageLoadSampleInputs, { usePreRun } from "./gdcm-read-image-load-sample-inputs.js" + +class GdcmReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class GdcmReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new GdcmReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#gdcmReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#gdcmReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("gdcmReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#gdcmReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#gdcmReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#gdcmReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'gdcmReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'gdcmReadImage') { + params.set('functionName', 'gdcmReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'gdcmReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'gdcmReadImage') { + tabGroup.show('gdcmReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#gdcmReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("gdcmReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("gdcmReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("gdcmReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("gdcmReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('gdcmReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.gdcmReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const gdcmReadImageController = new GdcmReadImageController(gdcmReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..d5cb4dffd --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gdcm-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function gdcmReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the gdcmReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#gdcmReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-controller.ts new file mode 100644 index 000000000..e35ab1b96 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import gdcmWriteImageLoadSampleInputs, { usePreRun } from "./gdcm-write-image-load-sample-inputs.js" + +class GdcmWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class GdcmWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new GdcmWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#gdcmWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#gdcmWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("gdcmWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#gdcmWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#gdcmWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#gdcmWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#gdcmWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#gdcmWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'gdcmWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'gdcmWriteImage') { + params.set('functionName', 'gdcmWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'gdcmWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'gdcmWriteImage') { + tabGroup.show('gdcmWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#gdcmWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("gdcmWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("gdcmWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("gdcmWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("gdcmWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.gdcmWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const gdcmWriteImageController = new GdcmWriteImageController(gdcmWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..b85679e97 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gdcm-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function gdcmWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the gdcmWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#gdcmWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-controller.ts new file mode 100644 index 000000000..9cf057d78 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import geAdwReadImageLoadSampleInputs, { usePreRun } from "./ge-adw-read-image-load-sample-inputs.js" + +class GeAdwReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class GeAdwReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new GeAdwReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#geAdwReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#geAdwReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("geAdwReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#geAdwReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#geAdwReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#geAdwReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'geAdwReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'geAdwReadImage') { + params.set('functionName', 'geAdwReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'geAdwReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'geAdwReadImage') { + tabGroup.show('geAdwReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#geAdwReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("geAdwReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("geAdwReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("geAdwReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("geAdwReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('geAdwReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.geAdwReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const geAdwReadImageController = new GeAdwReadImageController(geAdwReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..2c4b275de --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge-adw-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function geAdwReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the geAdwReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#geAdwReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-controller.ts new file mode 100644 index 000000000..a4a07d57d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import geAdwWriteImageLoadSampleInputs, { usePreRun } from "./ge-adw-write-image-load-sample-inputs.js" + +class GeAdwWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class GeAdwWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new GeAdwWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#geAdwWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#geAdwWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("geAdwWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#geAdwWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#geAdwWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#geAdwWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#geAdwWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#geAdwWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'geAdwWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'geAdwWriteImage') { + params.set('functionName', 'geAdwWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'geAdwWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'geAdwWriteImage') { + tabGroup.show('geAdwWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#geAdwWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("geAdwWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("geAdwWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("geAdwWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("geAdwWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.geAdwWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const geAdwWriteImageController = new GeAdwWriteImageController(geAdwWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..522f5221d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge-adw-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function geAdwWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the geAdwWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#geAdwWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/ge4-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/ge4-read-image-controller.ts new file mode 100644 index 000000000..c781473e9 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge4-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import ge4ReadImageLoadSampleInputs, { usePreRun } from "./ge4-read-image-load-sample-inputs.js" + +class Ge4ReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class Ge4ReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new Ge4ReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#ge4ReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#ge4ReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("ge4ReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#ge4ReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#ge4ReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#ge4ReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'ge4ReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'ge4ReadImage') { + params.set('functionName', 'ge4ReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'ge4ReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'ge4ReadImage') { + tabGroup.show('ge4ReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#ge4ReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("ge4ReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("ge4ReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("ge4ReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("ge4ReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('ge4ReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.ge4ReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const ge4ReadImageController = new Ge4ReadImageController(ge4ReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/ge4-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/ge4-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..1b01fffa8 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge4-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function ge4ReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the ge4ReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#ge4ReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/ge4-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/ge4-write-image-controller.ts new file mode 100644 index 000000000..3ba397d4e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge4-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import ge4WriteImageLoadSampleInputs, { usePreRun } from "./ge4-write-image-load-sample-inputs.js" + +class Ge4WriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class Ge4WriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new Ge4WriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#ge4WriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#ge4WriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("ge4WriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#ge4WriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#ge4WriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#ge4WriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#ge4WriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#ge4WriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'ge4WriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'ge4WriteImage') { + params.set('functionName', 'ge4WriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'ge4WriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'ge4WriteImage') { + tabGroup.show('ge4WriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#ge4WriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("ge4WriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("ge4WriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("ge4WriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("ge4WriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.ge4WriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const ge4WriteImageController = new Ge4WriteImageController(ge4WriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/ge4-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/ge4-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..5f19abb59 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge4-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function ge4WriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the ge4WriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#ge4WriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/ge5-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/ge5-read-image-controller.ts new file mode 100644 index 000000000..f4f3cb813 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge5-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import ge5ReadImageLoadSampleInputs, { usePreRun } from "./ge5-read-image-load-sample-inputs.js" + +class Ge5ReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class Ge5ReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new Ge5ReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#ge5ReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#ge5ReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("ge5ReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#ge5ReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#ge5ReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#ge5ReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'ge5ReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'ge5ReadImage') { + params.set('functionName', 'ge5ReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'ge5ReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'ge5ReadImage') { + tabGroup.show('ge5ReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#ge5ReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("ge5ReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("ge5ReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("ge5ReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("ge5ReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('ge5ReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.ge5ReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const ge5ReadImageController = new Ge5ReadImageController(ge5ReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/ge5-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/ge5-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..4889b51e2 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge5-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function ge5ReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the ge5ReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#ge5ReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/ge5-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/ge5-write-image-controller.ts new file mode 100644 index 000000000..8a08b06d1 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge5-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import ge5WriteImageLoadSampleInputs, { usePreRun } from "./ge5-write-image-load-sample-inputs.js" + +class Ge5WriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class Ge5WriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new Ge5WriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#ge5WriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#ge5WriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("ge5WriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#ge5WriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#ge5WriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#ge5WriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#ge5WriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#ge5WriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'ge5WriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'ge5WriteImage') { + params.set('functionName', 'ge5WriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'ge5WriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'ge5WriteImage') { + tabGroup.show('ge5WriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#ge5WriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("ge5WriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("ge5WriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("ge5WriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("ge5WriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.ge5WriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const ge5WriteImageController = new Ge5WriteImageController(ge5WriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/ge5-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/ge5-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..bb5b4edc1 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/ge5-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function ge5WriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the ge5WriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#ge5WriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/gipl-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/gipl-read-image-controller.ts new file mode 100644 index 000000000..4f17aa1a0 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gipl-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import giplReadImageLoadSampleInputs, { usePreRun } from "./gipl-read-image-load-sample-inputs.js" + +class GiplReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class GiplReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new GiplReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#giplReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#giplReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("giplReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#giplReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#giplReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#giplReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'giplReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'giplReadImage') { + params.set('functionName', 'giplReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'giplReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'giplReadImage') { + tabGroup.show('giplReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#giplReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("giplReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("giplReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("giplReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("giplReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('giplReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.giplReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const giplReadImageController = new GiplReadImageController(giplReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/gipl-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/gipl-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..b1c18b0ad --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gipl-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function giplReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the giplReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#giplReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/gipl-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/gipl-write-image-controller.ts new file mode 100644 index 000000000..a6c7f242e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gipl-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import giplWriteImageLoadSampleInputs, { usePreRun } from "./gipl-write-image-load-sample-inputs.js" + +class GiplWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class GiplWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new GiplWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#giplWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#giplWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("giplWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#giplWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#giplWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#giplWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#giplWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#giplWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'giplWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'giplWriteImage') { + params.set('functionName', 'giplWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'giplWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'giplWriteImage') { + tabGroup.show('giplWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#giplWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("giplWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("giplWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("giplWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("giplWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.giplWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const giplWriteImageController = new GiplWriteImageController(giplWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/gipl-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/gipl-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..08dd101ee --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/gipl-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function giplWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the giplWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#giplWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-controller.ts new file mode 100644 index 000000000..b58e905d5 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import hdf5ReadImageLoadSampleInputs, { usePreRun } from "./hdf5-read-image-load-sample-inputs.js" + +class Hdf5ReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class Hdf5ReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new Hdf5ReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#hdf5ReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#hdf5ReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("hdf5ReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#hdf5ReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#hdf5ReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#hdf5ReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'hdf5ReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'hdf5ReadImage') { + params.set('functionName', 'hdf5ReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'hdf5ReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'hdf5ReadImage') { + tabGroup.show('hdf5ReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#hdf5ReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("hdf5ReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("hdf5ReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("hdf5ReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("hdf5ReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('hdf5ReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.hdf5ReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const hdf5ReadImageController = new Hdf5ReadImageController(hdf5ReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..c7ca9eb9e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/hdf5-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function hdf5ReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the hdf5ReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#hdf5ReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-controller.ts new file mode 100644 index 000000000..a24042904 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import hdf5WriteImageLoadSampleInputs, { usePreRun } from "./hdf5-write-image-load-sample-inputs.js" + +class Hdf5WriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class Hdf5WriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new Hdf5WriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#hdf5WriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#hdf5WriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("hdf5WriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#hdf5WriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#hdf5WriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#hdf5WriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#hdf5WriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#hdf5WriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'hdf5WriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'hdf5WriteImage') { + params.set('functionName', 'hdf5WriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'hdf5WriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'hdf5WriteImage') { + tabGroup.show('hdf5WriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#hdf5WriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("hdf5WriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("hdf5WriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("hdf5WriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("hdf5WriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.hdf5WriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const hdf5WriteImageController = new Hdf5WriteImageController(hdf5WriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..de915924c --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/hdf5-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function hdf5WriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the hdf5WriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#hdf5WriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/index.ts b/packages/image-io/typescript/test/browser/demo-app/index.ts index 77eac8ee6..56f42ee20 100644 --- a/packages/image-io/typescript/test/browser/demo-app/index.ts +++ b/packages/image-io/typescript/test/browser/demo-app/index.ts @@ -1,13 +1,10 @@ -import * as imageIo from '../../../dist/bundles/image-io.js' +import * as imageIo from '../../../dist/index.js' globalThis.imageIo = imageIo // Use local, vendored WebAssembly module assets const pipelinesBaseUrl: string | URL = new URL('/pipelines', document.location.origin).href imageIo.setPipelinesBaseUrl(pipelinesBaseUrl) -const pipelineWorkerUrl: string | URL | null = new URL('/web-workers/pipeline.worker.js', document.location.origin).href -imageIo.setPipelineWorkerUrl(pipelineWorkerUrl) - const params = new URLSearchParams(window.location.search) if (!params.has('functionName')) { diff --git a/packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-controller.ts new file mode 100644 index 000000000..4948c8827 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import jpegReadImageLoadSampleInputs, { usePreRun } from "./jpeg-read-image-load-sample-inputs.js" + +class JpegReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class JpegReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new JpegReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#jpegReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#jpegReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("jpegReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#jpegReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#jpegReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#jpegReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'jpegReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'jpegReadImage') { + params.set('functionName', 'jpegReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'jpegReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'jpegReadImage') { + tabGroup.show('jpegReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#jpegReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("jpegReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("jpegReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("jpegReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("jpegReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('jpegReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.jpegReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const jpegReadImageController = new JpegReadImageController(jpegReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..1fdfa73b3 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/jpeg-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function jpegReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the jpegReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#jpegReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-controller.ts new file mode 100644 index 000000000..328d7060c --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import jpegWriteImageLoadSampleInputs, { usePreRun } from "./jpeg-write-image-load-sample-inputs.js" + +class JpegWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class JpegWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new JpegWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#jpegWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#jpegWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("jpegWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#jpegWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#jpegWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#jpegWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#jpegWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#jpegWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'jpegWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'jpegWriteImage') { + params.set('functionName', 'jpegWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'jpegWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'jpegWriteImage') { + tabGroup.show('jpegWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#jpegWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("jpegWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("jpegWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("jpegWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("jpegWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.jpegWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const jpegWriteImageController = new JpegWriteImageController(jpegWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..ac8760217 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/jpeg-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function jpegWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the jpegWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#jpegWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/lsm-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/lsm-read-image-controller.ts new file mode 100644 index 000000000..bb8b48e20 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/lsm-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import lsmReadImageLoadSampleInputs, { usePreRun } from "./lsm-read-image-load-sample-inputs.js" + +class LsmReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class LsmReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new LsmReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#lsmReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#lsmReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("lsmReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#lsmReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#lsmReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#lsmReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'lsmReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'lsmReadImage') { + params.set('functionName', 'lsmReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'lsmReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'lsmReadImage') { + tabGroup.show('lsmReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#lsmReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("lsmReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("lsmReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("lsmReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("lsmReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('lsmReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.lsmReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const lsmReadImageController = new LsmReadImageController(lsmReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/lsm-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/lsm-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..d28f8314e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/lsm-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function lsmReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the lsmReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#lsmReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/lsm-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/lsm-write-image-controller.ts new file mode 100644 index 000000000..0deaeb6da --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/lsm-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import lsmWriteImageLoadSampleInputs, { usePreRun } from "./lsm-write-image-load-sample-inputs.js" + +class LsmWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class LsmWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new LsmWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#lsmWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#lsmWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("lsmWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#lsmWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#lsmWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#lsmWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#lsmWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#lsmWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'lsmWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'lsmWriteImage') { + params.set('functionName', 'lsmWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'lsmWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'lsmWriteImage') { + tabGroup.show('lsmWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#lsmWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("lsmWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("lsmWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("lsmWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("lsmWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.lsmWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const lsmWriteImageController = new LsmWriteImageController(lsmWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/lsm-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/lsm-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..b8fd17cd8 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/lsm-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function lsmWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the lsmWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#lsmWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/meta-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/meta-read-image-controller.ts new file mode 100644 index 000000000..42fed3bd0 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/meta-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import metaReadImageLoadSampleInputs, { usePreRun } from "./meta-read-image-load-sample-inputs.js" + +class MetaReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MetaReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MetaReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#metaReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#metaReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("metaReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#metaReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#metaReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#metaReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'metaReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'metaReadImage') { + params.set('functionName', 'metaReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'metaReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'metaReadImage') { + tabGroup.show('metaReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#metaReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("metaReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("metaReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("metaReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("metaReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('metaReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.metaReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const metaReadImageController = new MetaReadImageController(metaReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/meta-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/meta-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..c06b041b4 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/meta-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function metaReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the metaReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#metaReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/meta-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/meta-write-image-controller.ts new file mode 100644 index 000000000..93c287678 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/meta-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import metaWriteImageLoadSampleInputs, { usePreRun } from "./meta-write-image-load-sample-inputs.js" + +class MetaWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MetaWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MetaWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#metaWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#metaWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("metaWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#metaWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#metaWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#metaWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#metaWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#metaWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'metaWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'metaWriteImage') { + params.set('functionName', 'metaWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'metaWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'metaWriteImage') { + tabGroup.show('metaWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#metaWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("metaWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("metaWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("metaWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("metaWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.metaWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const metaWriteImageController = new MetaWriteImageController(metaWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/meta-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/meta-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..3da58f842 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/meta-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function metaWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the metaWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#metaWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/mgh-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/mgh-read-image-controller.ts new file mode 100644 index 000000000..58ae494b3 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mgh-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import mghReadImageLoadSampleInputs, { usePreRun } from "./mgh-read-image-load-sample-inputs.js" + +class MghReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MghReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MghReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#mghReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#mghReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("mghReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#mghReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#mghReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#mghReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'mghReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'mghReadImage') { + params.set('functionName', 'mghReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'mghReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'mghReadImage') { + tabGroup.show('mghReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#mghReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("mghReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("mghReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("mghReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("mghReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('mghReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.mghReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const mghReadImageController = new MghReadImageController(mghReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/mgh-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/mgh-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..6ca930851 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mgh-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function mghReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the mghReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#mghReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/mgh-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/mgh-write-image-controller.ts new file mode 100644 index 000000000..b4d064c30 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mgh-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import mghWriteImageLoadSampleInputs, { usePreRun } from "./mgh-write-image-load-sample-inputs.js" + +class MghWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MghWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MghWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#mghWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#mghWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("mghWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#mghWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#mghWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#mghWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#mghWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#mghWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'mghWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'mghWriteImage') { + params.set('functionName', 'mghWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'mghWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'mghWriteImage') { + tabGroup.show('mghWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#mghWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("mghWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("mghWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("mghWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("mghWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.mghWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const mghWriteImageController = new MghWriteImageController(mghWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/mgh-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/mgh-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..82565e19d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mgh-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function mghWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the mghWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#mghWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/minc-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/minc-read-image-controller.ts new file mode 100644 index 000000000..e08b88b8d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/minc-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import mincReadImageLoadSampleInputs, { usePreRun } from "./minc-read-image-load-sample-inputs.js" + +class MincReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MincReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MincReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#mincReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#mincReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("mincReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#mincReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#mincReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#mincReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'mincReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'mincReadImage') { + params.set('functionName', 'mincReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'mincReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'mincReadImage') { + tabGroup.show('mincReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#mincReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("mincReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("mincReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("mincReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("mincReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('mincReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.mincReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const mincReadImageController = new MincReadImageController(mincReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/minc-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/minc-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..424e9cfb9 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/minc-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function mincReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the mincReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#mincReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/minc-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/minc-write-image-controller.ts new file mode 100644 index 000000000..b17b4570d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/minc-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import mincWriteImageLoadSampleInputs, { usePreRun } from "./minc-write-image-load-sample-inputs.js" + +class MincWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MincWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MincWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#mincWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#mincWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("mincWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#mincWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#mincWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#mincWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#mincWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#mincWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'mincWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'mincWriteImage') { + params.set('functionName', 'mincWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'mincWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'mincWriteImage') { + tabGroup.show('mincWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#mincWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("mincWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("mincWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("mincWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("mincWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.mincWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const mincWriteImageController = new MincWriteImageController(mincWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/minc-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/minc-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..687165dce --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/minc-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function mincWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the mincWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#mincWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/mrc-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/mrc-read-image-controller.ts new file mode 100644 index 000000000..f1ed28ba1 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mrc-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import mrcReadImageLoadSampleInputs, { usePreRun } from "./mrc-read-image-load-sample-inputs.js" + +class MrcReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MrcReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MrcReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#mrcReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#mrcReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("mrcReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#mrcReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#mrcReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#mrcReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'mrcReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'mrcReadImage') { + params.set('functionName', 'mrcReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'mrcReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'mrcReadImage') { + tabGroup.show('mrcReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#mrcReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("mrcReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("mrcReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("mrcReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("mrcReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('mrcReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.mrcReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const mrcReadImageController = new MrcReadImageController(mrcReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/mrc-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/mrc-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..d0c8c96e9 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mrc-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function mrcReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the mrcReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#mrcReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/mrc-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/mrc-write-image-controller.ts new file mode 100644 index 000000000..dd018d7ef --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mrc-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import mrcWriteImageLoadSampleInputs, { usePreRun } from "./mrc-write-image-load-sample-inputs.js" + +class MrcWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class MrcWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new MrcWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#mrcWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#mrcWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("mrcWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#mrcWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#mrcWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#mrcWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#mrcWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#mrcWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'mrcWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'mrcWriteImage') { + params.set('functionName', 'mrcWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'mrcWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'mrcWriteImage') { + tabGroup.show('mrcWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#mrcWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("mrcWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("mrcWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("mrcWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("mrcWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.mrcWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const mrcWriteImageController = new MrcWriteImageController(mrcWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/mrc-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/mrc-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..49b5997d5 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/mrc-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function mrcWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the mrcWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#mrcWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/nifti-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/nifti-read-image-controller.ts new file mode 100644 index 000000000..15b46bf70 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nifti-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import niftiReadImageLoadSampleInputs, { usePreRun } from "./nifti-read-image-load-sample-inputs.js" + +class NiftiReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class NiftiReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new NiftiReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#niftiReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#niftiReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("niftiReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#niftiReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#niftiReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#niftiReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'niftiReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'niftiReadImage') { + params.set('functionName', 'niftiReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'niftiReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'niftiReadImage') { + tabGroup.show('niftiReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#niftiReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("niftiReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("niftiReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("niftiReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("niftiReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('niftiReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.niftiReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const niftiReadImageController = new NiftiReadImageController(niftiReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/nifti-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/nifti-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..917696ef0 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nifti-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function niftiReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the niftiReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#niftiReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/nifti-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/nifti-write-image-controller.ts new file mode 100644 index 000000000..f59897e36 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nifti-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import niftiWriteImageLoadSampleInputs, { usePreRun } from "./nifti-write-image-load-sample-inputs.js" + +class NiftiWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class NiftiWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new NiftiWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#niftiWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#niftiWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("niftiWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#niftiWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#niftiWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#niftiWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#niftiWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#niftiWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'niftiWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'niftiWriteImage') { + params.set('functionName', 'niftiWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'niftiWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'niftiWriteImage') { + tabGroup.show('niftiWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#niftiWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("niftiWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("niftiWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("niftiWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("niftiWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.niftiWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const niftiWriteImageController = new NiftiWriteImageController(niftiWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/nifti-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/nifti-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..9cb983c14 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nifti-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function niftiWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the niftiWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#niftiWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-controller.ts new file mode 100644 index 000000000..cee311e8e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import nrrdReadImageLoadSampleInputs, { usePreRun } from "./nrrd-read-image-load-sample-inputs.js" + +class NrrdReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class NrrdReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new NrrdReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#nrrdReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#nrrdReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("nrrdReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#nrrdReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#nrrdReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#nrrdReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'nrrdReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'nrrdReadImage') { + params.set('functionName', 'nrrdReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'nrrdReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'nrrdReadImage') { + tabGroup.show('nrrdReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#nrrdReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("nrrdReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("nrrdReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("nrrdReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("nrrdReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('nrrdReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.nrrdReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const nrrdReadImageController = new NrrdReadImageController(nrrdReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..0c32c0d24 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nrrd-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function nrrdReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the nrrdReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#nrrdReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-controller.ts new file mode 100644 index 000000000..ee073f790 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import nrrdWriteImageLoadSampleInputs, { usePreRun } from "./nrrd-write-image-load-sample-inputs.js" + +class NrrdWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class NrrdWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new NrrdWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#nrrdWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#nrrdWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("nrrdWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#nrrdWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#nrrdWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#nrrdWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#nrrdWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#nrrdWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'nrrdWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'nrrdWriteImage') { + params.set('functionName', 'nrrdWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'nrrdWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'nrrdWriteImage') { + tabGroup.show('nrrdWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#nrrdWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("nrrdWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("nrrdWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("nrrdWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("nrrdWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.nrrdWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const nrrdWriteImageController = new NrrdWriteImageController(nrrdWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..14c19e0db --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/nrrd-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function nrrdWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the nrrdWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#nrrdWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/png-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/png-read-image-controller.ts new file mode 100644 index 000000000..886d35f2b --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/png-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import pngReadImageLoadSampleInputs, { usePreRun } from "./png-read-image-load-sample-inputs.js" + +class PngReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class PngReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new PngReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#pngReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#pngReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("pngReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#pngReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#pngReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#pngReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'pngReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'pngReadImage') { + params.set('functionName', 'pngReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'pngReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'pngReadImage') { + tabGroup.show('pngReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#pngReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("pngReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("pngReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("pngReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("pngReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('pngReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.pngReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const pngReadImageController = new PngReadImageController(pngReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/png-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/png-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..8d93ca414 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/png-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function pngReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the pngReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#pngReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/png-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/png-write-image-controller.ts new file mode 100644 index 000000000..4e2164376 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/png-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import pngWriteImageLoadSampleInputs, { usePreRun } from "./png-write-image-load-sample-inputs.js" + +class PngWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class PngWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new PngWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#pngWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#pngWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("pngWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#pngWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#pngWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#pngWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#pngWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#pngWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'pngWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'pngWriteImage') { + params.set('functionName', 'pngWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'pngWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'pngWriteImage') { + tabGroup.show('pngWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#pngWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("pngWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("pngWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("pngWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("pngWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.pngWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const pngWriteImageController = new PngWriteImageController(pngWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/png-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/png-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..2fd354f0d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/png-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function pngWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the pngWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#pngWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/read-image-controller.ts index 8408f6f30..88bfca720 100644 --- a/packages/image-io/typescript/test/browser/demo-app/read-image-controller.ts +++ b/packages/image-io/typescript/test/browser/demo-app/read-image-controller.ts @@ -1,6 +1,5 @@ -import { writeImageArrayBuffer } from 'itk-wasm' import { copyImage } from 'itk-wasm' -import * as imageIo from '../../../dist/bundles/image-io.js' +import * as imageIo from '../../../dist/index.js' import readImageLoadSampleInputs, { usePreRun } from "./read-image-load-sample-inputs.js" class ReadImageModel { @@ -68,10 +67,10 @@ class ReadImageController { const imageDownloadFormat = document.getElementById('image-output-format') const downloadFormat = imageDownloadFormat.value || 'nrrd' const fileName = `image.${downloadFormat}` - const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("image")), fileName) + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) webWorker.terminate() - globalThis.downloadFile(arrayBuffer, fileName) + globalThis.downloadFile(serializedImage, fileName) } }) diff --git a/packages/image-io/typescript/test/browser/demo-app/scanco-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/scanco-read-image-controller.ts new file mode 100644 index 000000000..17526ae17 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/scanco-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import scancoReadImageLoadSampleInputs, { usePreRun } from "./scanco-read-image-load-sample-inputs.js" + +class ScancoReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class ScancoReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new ScancoReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#scancoReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#scancoReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("scancoReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#scancoReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#scancoReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#scancoReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'scancoReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'scancoReadImage') { + params.set('functionName', 'scancoReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'scancoReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'scancoReadImage') { + tabGroup.show('scancoReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#scancoReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("scancoReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("scancoReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("scancoReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("scancoReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('scancoReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.scancoReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const scancoReadImageController = new ScancoReadImageController(scancoReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/scanco-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/scanco-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..a4cba708a --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/scanco-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function scancoReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the scancoReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#scancoReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/scanco-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/scanco-write-image-controller.ts new file mode 100644 index 000000000..b7446573e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/scanco-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import scancoWriteImageLoadSampleInputs, { usePreRun } from "./scanco-write-image-load-sample-inputs.js" + +class ScancoWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class ScancoWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new ScancoWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#scancoWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#scancoWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("scancoWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#scancoWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#scancoWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#scancoWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#scancoWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#scancoWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'scancoWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'scancoWriteImage') { + params.set('functionName', 'scancoWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'scancoWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'scancoWriteImage') { + tabGroup.show('scancoWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#scancoWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("scancoWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("scancoWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("scancoWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("scancoWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.scancoWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const scancoWriteImageController = new ScancoWriteImageController(scancoWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/scanco-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/scanco-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..f648d6f58 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/scanco-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function scancoWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the scancoWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#scancoWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/tiff-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/tiff-read-image-controller.ts new file mode 100644 index 000000000..5201f342e --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/tiff-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import tiffReadImageLoadSampleInputs, { usePreRun } from "./tiff-read-image-load-sample-inputs.js" + +class TiffReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class TiffReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new TiffReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#tiffReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#tiffReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("tiffReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#tiffReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#tiffReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#tiffReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'tiffReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'tiffReadImage') { + params.set('functionName', 'tiffReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'tiffReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'tiffReadImage') { + tabGroup.show('tiffReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#tiffReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("tiffReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("tiffReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("tiffReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("tiffReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('tiffReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.tiffReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const tiffReadImageController = new TiffReadImageController(tiffReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/tiff-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/tiff-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..7d54fbf60 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/tiff-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function tiffReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the tiffReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#tiffReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/tiff-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/tiff-write-image-controller.ts new file mode 100644 index 000000000..a7e87fad8 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/tiff-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import tiffWriteImageLoadSampleInputs, { usePreRun } from "./tiff-write-image-load-sample-inputs.js" + +class TiffWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class TiffWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new TiffWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#tiffWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#tiffWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("tiffWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#tiffWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#tiffWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#tiffWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#tiffWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#tiffWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'tiffWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'tiffWriteImage') { + params.set('functionName', 'tiffWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'tiffWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'tiffWriteImage') { + tabGroup.show('tiffWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#tiffWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("tiffWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("tiffWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("tiffWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("tiffWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.tiffWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const tiffWriteImageController = new TiffWriteImageController(tiffWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/tiff-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/tiff-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..2f391059d --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/tiff-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function tiffWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the tiffWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#tiffWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/vtk-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/vtk-read-image-controller.ts new file mode 100644 index 000000000..76eb0f72a --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/vtk-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import vtkReadImageLoadSampleInputs, { usePreRun } from "./vtk-read-image-load-sample-inputs.js" + +class VtkReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class VtkReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new VtkReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#vtkReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#vtkReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("vtkReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#vtkReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#vtkReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#vtkReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'vtkReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'vtkReadImage') { + params.set('functionName', 'vtkReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'vtkReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'vtkReadImage') { + tabGroup.show('vtkReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#vtkReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("vtkReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("vtkReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("vtkReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("vtkReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('vtkReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.vtkReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const vtkReadImageController = new VtkReadImageController(vtkReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/vtk-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/vtk-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..7d8d08183 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/vtk-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function vtkReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the vtkReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#vtkReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/vtk-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/vtk-write-image-controller.ts new file mode 100644 index 000000000..26b40ded4 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/vtk-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import vtkWriteImageLoadSampleInputs, { usePreRun } from "./vtk-write-image-load-sample-inputs.js" + +class VtkWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class VtkWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new VtkWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#vtkWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#vtkWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("vtkWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#vtkWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#vtkWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#vtkWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#vtkWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#vtkWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'vtkWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'vtkWriteImage') { + params.set('functionName', 'vtkWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'vtkWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'vtkWriteImage') { + tabGroup.show('vtkWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#vtkWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("vtkWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("vtkWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("vtkWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("vtkWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.vtkWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const vtkWriteImageController = new VtkWriteImageController(vtkWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/vtk-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/vtk-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..5a454c46c --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/vtk-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function vtkWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the vtkWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#vtkWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-read-image-controller.ts new file mode 100644 index 000000000..4daed13e8 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import wasmReadImageLoadSampleInputs, { usePreRun } from "./wasm-read-image-load-sample-inputs.js" + +class WasmReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class WasmReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new WasmReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#wasmReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#wasmReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("wasmReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#wasmReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#wasmReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#wasmReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'wasmReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'wasmReadImage') { + params.set('functionName', 'wasmReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'wasmReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'wasmReadImage') { + tabGroup.show('wasmReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#wasmReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("wasmReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("wasmReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("wasmReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("wasmReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('wasmReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.wasmReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const wasmReadImageController = new WasmReadImageController(wasmReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..0f033538f --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function wasmReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the wasmReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#wasmReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-write-image-controller.ts new file mode 100644 index 000000000..5bb051fe1 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import wasmWriteImageLoadSampleInputs, { usePreRun } from "./wasm-write-image-load-sample-inputs.js" + +class WasmWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class WasmWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new WasmWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#wasmWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#wasmWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("wasmWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#wasmWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#wasmWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#wasmWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#wasmWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#wasmWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'wasmWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'wasmWriteImage') { + params.set('functionName', 'wasmWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'wasmWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'wasmWriteImage') { + tabGroup.show('wasmWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#wasmWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("wasmWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("wasmWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("wasmWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("wasmWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.wasmWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const wasmWriteImageController = new WasmWriteImageController(wasmWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..90ffd472c --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function wasmWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the wasmWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#wasmWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-controller.ts new file mode 100644 index 000000000..22fce7282 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-controller.ts @@ -0,0 +1,172 @@ + +import { writeImageArrayBuffer } from 'itk-wasm' +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import wasmZstdReadImageLoadSampleInputs, { usePreRun } from "./wasm-zstd-read-image-load-sample-inputs.js" + +class WasmZstdReadImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class WasmZstdReadImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new WasmZstdReadImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#wasmZstdReadImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const serializedImageElement = document.querySelector('#wasmZstdReadImageInputs input[name=serialized-image-file]') + serializedImageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const arrayBuffer = await files[0].arrayBuffer() + model.inputs.set("serializedImage", { data: new Uint8Array(arrayBuffer), path: files[0].name }) + const details = document.getElementById("wasmZstdReadImage-serialized-image-details") + details.innerHTML = `
${globalThis.escapeHtml(model.inputs.get("serializedImage").data.subarray(0, 50).toString() + ' ...')}
` + details.disabled = false + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#wasmZstdReadImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldReadOutputDownload = document.querySelector('#wasmZstdReadImageOutputs sl-button[name=could-read-download]') + couldReadOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldRead")) { + const fileName = `couldRead.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldRead"))), fileName) + } + }) + + const imageOutputDownload = document.querySelector('#wasmZstdReadImageOutputs sl-button[name=image-download]') + imageOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("image")) { + const imageDownloadFormat = document.getElementById('image-output-format') + const downloadFormat = imageDownloadFormat.value || 'nrrd' + const fileName = `image.${downloadFormat}` + const { webWorker, serializedImage } = await imageIo.writeImage(null, copyImage(model.outputs.get("image")), fileName) + + webWorker.terminate() + globalThis.downloadFile(serializedImage, fileName) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'wasmZstdReadImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'wasmZstdReadImage') { + params.set('functionName', 'wasmZstdReadImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'wasmZstdReadImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'wasmZstdReadImage') { + tabGroup.show('wasmZstdReadImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#wasmZstdReadImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('serializedImage')) { + globalThis.notify("Required input not provided", "serializedImage", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldRead, image, } = await this.run() + const t1 = performance.now() + globalThis.notify("wasmZstdReadImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldRead", couldRead) + couldReadOutputDownload.variant = "success" + couldReadOutputDownload.disabled = false + const couldReadDetails = document.getElementById("wasmZstdReadImage-could-read-details") + couldReadDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldRead, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldReadDetails.disabled = false + const couldReadOutput = document.getElementById("wasmZstdReadImage-could-read-details") + + model.outputs.set("image", image) + imageOutputDownload.variant = "success" + imageOutputDownload.disabled = false + const imageDetails = document.getElementById("wasmZstdReadImage-image-details") + imageDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + imageDetails.disabled = false + const imageOutput = document.getElementById('wasmZstdReadImage-image-details') + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldRead, image, } = await imageIo.wasmZstdReadImage(this.webWorker, + { data: this.model.inputs.get('serializedImage').data.slice(), path: this.model.inputs.get('serializedImage').path }, + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldRead, image, } + } +} + +const wasmZstdReadImageController = new WasmZstdReadImageController(wasmZstdReadImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-load-sample-inputs.ts new file mode 100644 index 000000000..9061cb647 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-read-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function wasmZstdReadImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the wasmZstdReadImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#wasmZstdReadImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-controller.ts new file mode 100644 index 000000000..68fbba770 --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-controller.ts @@ -0,0 +1,176 @@ + +import { copyImage } from 'itk-wasm' +import * as imageIo from '../../../dist/index.js' +import wasmZstdWriteImageLoadSampleInputs, { usePreRun } from "./wasm-zstd-write-image-load-sample-inputs.js" + +class WasmZstdWriteImageModel { + inputs: Map + options: Map + outputs: Map + + constructor() { + this.inputs = new Map() + this.options = new Map() + this.outputs = new Map() + } +} + + +class WasmZstdWriteImageController { + + constructor(loadSampleInputs) { + this.loadSampleInputs = loadSampleInputs + + this.model = new WasmZstdWriteImageModel() + const model = this.model + + this.webWorker = null + + if (loadSampleInputs) { + const loadSampleInputsButton = document.querySelector("#wasmZstdWriteImageInputs [name=loadSampleInputs]") + loadSampleInputsButton.setAttribute('style', 'display: block-inline;') + loadSampleInputsButton.addEventListener('click', async (event) => { + loadSampleInputsButton.loading = true + await loadSampleInputs(model) + loadSampleInputsButton.loading = false + }) + } + + // ---------------------------------------------- + // Inputs + const imageElement = document.querySelector('#wasmZstdWriteImageInputs input[name=image-file]') + imageElement.addEventListener('change', async (event) => { + const dataTransfer = event.dataTransfer + const files = event.target.files || dataTransfer.files + + const { image, webWorker } = await imageIo.readImage(null, files[0]) + webWorker.terminate() + model.inputs.set("image", image) + const details = document.getElementById("wasmZstdWriteImage-image-details") + details.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(image, globalThis.interfaceTypeJsonReplacer, 2))}
` + details.disabled = false + }) + + const serializedImageElement = document.querySelector('#wasmZstdWriteImageInputs sl-input[name=serialized-image]') + serializedImageElement.addEventListener('sl-change', (event) => { + model.inputs.set("serializedImage", serializedImageElement.value) + }) + + // ---------------------------------------------- + // Options + const informationOnlyElement = document.querySelector('#wasmZstdWriteImageInputs sl-checkbox[name=information-only]') + informationOnlyElement.addEventListener('sl-change', (event) => { + model.options.set("informationOnly", informationOnlyElement.checked) + }) + + const useCompressionElement = document.querySelector('#wasmZstdWriteImageInputs sl-checkbox[name=use-compression]') + useCompressionElement.addEventListener('sl-change', (event) => { + model.options.set("useCompression", useCompressionElement.checked) + }) + + // ---------------------------------------------- + // Outputs + const couldWriteOutputDownload = document.querySelector('#wasmZstdWriteImageOutputs sl-button[name=could-write-download]') + couldWriteOutputDownload.addEventListener('click', async (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("couldWrite")) { + const fileName = `couldWrite.json` + globalThis.downloadFile(new TextEncoder().encode(JSON.stringify(model.outputs.get("couldWrite"))), fileName) + } + }) + + const serializedImageOutputDownload = document.querySelector('#wasmZstdWriteImageOutputs sl-button[name=serialized-image-download]') + serializedImageOutputDownload.addEventListener('click', (event) => { + event.preventDefault() + event.stopPropagation() + if (model.outputs.has("serializedImage")) { + globalThis.downloadFile(model.outputs.get("serializedImage").data, model.outputs.get("serializedImage").path) + } + }) + + const preRun = async () => { + if (!this.webWorker && loadSampleInputs && usePreRun) { + await loadSampleInputs(model, true) + await this.run() + } + } + + const onSelectTab = async (event) => { + if (event.detail.name === 'wasmZstdWriteImage-panel') { + const params = new URLSearchParams(window.location.search) + if (!params.has('functionName') || params.get('functionName') !== 'wasmZstdWriteImage') { + params.set('functionName', 'wasmZstdWriteImage') + const url = new URL(document.location) + url.search = params + window.history.replaceState({ functionName: 'wasmZstdWriteImage' }, '', url) + await preRun() + } + } + } + + const tabGroup = document.querySelector('sl-tab-group') + tabGroup.addEventListener('sl-tab-show', onSelectTab) + function onInit() { + const params = new URLSearchParams(window.location.search) + if (params.has('functionName') && params.get('functionName') === 'wasmZstdWriteImage') { + tabGroup.show('wasmZstdWriteImage-panel') + preRun() + } + } + onInit() + + const runButton = document.querySelector('#wasmZstdWriteImageInputs sl-button[name="run"]') + runButton.addEventListener('click', async (event) => { + event.preventDefault() + + if(!model.inputs.has('image')) { + globalThis.notify("Required input not provided", "image", "danger", "exclamation-octagon") + return + } + + + try { + runButton.loading = true + + const t0 = performance.now() + const { couldWrite, serializedImage, } = await this.run() + const t1 = performance.now() + globalThis.notify("wasmZstdWriteImage successfully completed", `in ${t1 - t0} milliseconds.`, "success", "rocket-fill") + + model.outputs.set("couldWrite", couldWrite) + couldWriteOutputDownload.variant = "success" + couldWriteOutputDownload.disabled = false + const couldWriteDetails = document.getElementById("wasmZstdWriteImage-could-write-details") + couldWriteDetails.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(couldWrite, globalThis.interfaceTypeJsonReplacer, 2))}
` + couldWriteDetails.disabled = false + const couldWriteOutput = document.getElementById("wasmZstdWriteImage-could-write-details") + + model.outputs.set("serializedImage", serializedImage) + serializedImageOutputDownload.variant = "success" + serializedImageOutputDownload.disabled = false + const serializedImageOutput = document.getElementById("wasmZstdWriteImage-serialized-image-details") + serializedImageOutput.innerHTML = `
${globalThis.escapeHtml(serializedImage.data.subarray(0, 1024).toString() + ' ...')}
` + serializedImageOutput.disabled = false + } catch (error) { + globalThis.notify("Error while running pipeline", error.toString(), "danger", "exclamation-octagon") + throw error + } finally { + runButton.loading = false + } + }) + } + + async run() { + const { webWorker, couldWrite, serializedImage, } = await imageIo.wasmZstdWriteImage(this.webWorker, + copyImage(this.model.inputs.get('image')), + this.model.inputs.get('serializedImage'), + Object.fromEntries(this.model.options.entries()) + ) + this.webWorker = webWorker + + return { couldWrite, serializedImage, } + } +} + +const wasmZstdWriteImageController = new WasmZstdWriteImageController(wasmZstdWriteImageLoadSampleInputs) diff --git a/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-load-sample-inputs.ts new file mode 100644 index 000000000..5cc2a91fb --- /dev/null +++ b/packages/image-io/typescript/test/browser/demo-app/wasm-zstd-write-image-load-sample-inputs.ts @@ -0,0 +1,28 @@ +// Generated file. To retain edits, remove this comment. + +export default null +// export default async function wasmZstdWriteImageLoadSampleInputs (model, preRun=false) { + + // Load sample inputs for the wasmZstdWriteImage function. + // + // This function should load sample inputs: + // + // 1) In the provided model map. + // 2) Into the corresponding HTML input elements if preRun is not true. + // + // Example for an input named `exampleInput`: + + // const exampleInput = 5 + // model.inputs.set("exampleInput", exampleInput) + // if (!preRun) { + // const exampleElement = document.querySelector("#wasmZstdWriteImageInputs [name=example-input]") + // exampleElement.value = 5 + // } + + // return model +// } + +// Use this function to run the pipeline when this tab group is select. +// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. +// Set this to `false` if sample inputs are very large or sample pipeline computation is long. +export const usePreRun = true diff --git a/packages/image-io/typescript/test/browser/demo-app/write-image-controller.ts b/packages/image-io/typescript/test/browser/demo-app/write-image-controller.ts index c66cfb92f..840a36598 100644 --- a/packages/image-io/typescript/test/browser/demo-app/write-image-controller.ts +++ b/packages/image-io/typescript/test/browser/demo-app/write-image-controller.ts @@ -1,6 +1,5 @@ -import { readImageFile } from 'itk-wasm' import { copyImage } from 'itk-wasm' -import * as imageIo from '../../../dist/bundles/image-io.js' +import * as imageIo from '../../../dist/index.js' import writeImageLoadSampleInputs, { usePreRun } from "./write-image-load-sample-inputs.js" class WriteImageModel { @@ -43,7 +42,7 @@ class WriteImageController { const dataTransfer = event.dataTransfer const files = event.target.files || dataTransfer.files - const { image, webWorker } = await readImageFile(null, files[0]) + const { image, webWorker } = await imageIo.readImage(null, files[0]) webWorker.terminate() model.inputs.set("image", image) const details = document.getElementById("writeImage-image-details") diff --git a/packages/image-io/typescript/test/browser/demo-app/write-image-load-sample-inputs.ts b/packages/image-io/typescript/test/browser/demo-app/write-image-load-sample-inputs.ts index d6ba20cfc..66281ffce 100644 --- a/packages/image-io/typescript/test/browser/demo-app/write-image-load-sample-inputs.ts +++ b/packages/image-io/typescript/test/browser/demo-app/write-image-load-sample-inputs.ts @@ -1,28 +1,29 @@ -// Generated file. To retain edits, remove this comment. +import * as imageIo from '../../../dist/index.js' -export default null -// export default async function bioRadWriteImageLoadSampleInputs (model, preRun=false) { +export default async function writeImageLoadSampleInputs (model, preRun=false) { - // Load sample inputs for the bioRadWriteImage function. - // - // This function should load sample inputs: - // - // 1) In the provided model map. - // 2) Into the corresponding HTML input elements if preRun is not true. - // - // Example for an input named `exampleInput`: + const inputButton = document.querySelector('#writeImageInputs sl-button[name=image-file-button]') + if (!preRun) { + inputButton.loading = true + } + const fileName = 'cthead1.iwi.cbor' + const inputResponse = await fetch(`https://bafybeigrnfohpfr2kqooyjsozsva6jh2663riwrxsum5x3ltow42r6j2o4.ipfs.w3s.link/ipfs/bafybeigrnfohpfr2kqooyjsozsva6jh2663riwrxsum5x3ltow42r6j2o4/data/input/${fileName}`) + const inputData = new Uint8Array(await inputResponse.arrayBuffer()) + const { image: inputImage, webWorker } = await imageIo.readImage(null, { data: inputData, path: fileName }) + webWorker.terminate() + model.inputs.set('image', inputImage) + const serializedImage = 'cthead1.png' + model.inputs.set('serializedImage', serializedImage) + if (!preRun) { + const detailsElement = document.querySelector('#writeImage-image-details') + detailsElement.innerHTML = `
${globalThis.escapeHtml(JSON.stringify(inputImage, globalThis.interfaceTypeJsonReplacer, 2))}
` + detailsElement.disabled = false + const inputElement = document.querySelector('#writeImageInputs sl-input[name="serialized-image"]') + inputElement.value = serializedImage + inputButton.loading = false + } - // const exampleInput = 5 - // model.inputs.set("exampleInput", exampleInput) - // if (!preRun) { - // const exampleElement = document.querySelector("#bioRadWriteImageInputs [name=example-input]") - // exampleElement.value = 5 - // } + return model +} - // return model -// } - -// Use this function to run the pipeline when this tab group is select. -// This will load the web worker if it is not already loaded, download the wasm module, and allocate memory in the wasm model. -// Set this to `false` if sample inputs are very large or sample pipeline computation is long. export const usePreRun = true diff --git a/packages/image-io/typescript/test/node/bio-rad-test.js b/packages/image-io/typescript/test/node/bio-rad-test.js index c32931cd3..2e25d8124 100644 --- a/packages/image-io/typescript/test/node/bio-rad-test.js +++ b/packages/image-io/typescript/test/node/bio-rad-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { bioRadReadImageNode, bioRadWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { bioRadReadImageNode, bioRadWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/bmp-test.js b/packages/image-io/typescript/test/node/bmp-test.js index 443de836a..77a882bd3 100644 --- a/packages/image-io/typescript/test/node/bmp-test.js +++ b/packages/image-io/typescript/test/node/bmp-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { bmpReadImageNode } from '../../dist/bundles/image-io-node.js' +import { bmpReadImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/fdf-test.js b/packages/image-io/typescript/test/node/fdf-test.js index f9fc71eab..ac89e4866 100644 --- a/packages/image-io/typescript/test/node/fdf-test.js +++ b/packages/image-io/typescript/test/node/fdf-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { fdfReadImageNode } from '../../dist/bundles/image-io-node.js' +import { fdfReadImageNode } from '../../dist/index-node.js' import { FloatTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/hdf5-test.js b/packages/image-io/typescript/test/node/hdf5-test.js index 564b69755..0a682afdd 100644 --- a/packages/image-io/typescript/test/node/hdf5-test.js +++ b/packages/image-io/typescript/test/node/hdf5-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { hdf5ReadImageNode } from '../../dist/bundles/image-io-node.js' +import { hdf5ReadImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/jpeg-test.js b/packages/image-io/typescript/test/node/jpeg-test.js index 960137a43..27d33c0e5 100644 --- a/packages/image-io/typescript/test/node/jpeg-test.js +++ b/packages/image-io/typescript/test/node/jpeg-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { jpegReadImageNode } from '../../dist/bundles/image-io-node.js' +import { jpegReadImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/lsm-test.js b/packages/image-io/typescript/test/node/lsm-test.js index c28afa7ef..575a35ee7 100644 --- a/packages/image-io/typescript/test/node/lsm-test.js +++ b/packages/image-io/typescript/test/node/lsm-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { lsmReadImageNode } from '../../dist/bundles/image-io-node.js' +import { lsmReadImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/meta-image-test.js b/packages/image-io/typescript/test/node/meta-image-test.js index 22eb56619..8ccd90a29 100644 --- a/packages/image-io/typescript/test/node/meta-image-test.js +++ b/packages/image-io/typescript/test/node/meta-image-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { metaReadImageNode, metaWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { metaReadImageNode, metaWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/mgh-test.js b/packages/image-io/typescript/test/node/mgh-test.js index 3562bcfb3..a2b825ecd 100644 --- a/packages/image-io/typescript/test/node/mgh-test.js +++ b/packages/image-io/typescript/test/node/mgh-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { mghReadImageNode, mghWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { mghReadImageNode, mghWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/minc-test.js b/packages/image-io/typescript/test/node/minc-test.js index bdaaf4f7e..659ba22b0 100644 --- a/packages/image-io/typescript/test/node/minc-test.js +++ b/packages/image-io/typescript/test/node/minc-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { mincReadImageNode } from '../../dist/bundles/image-io-node.js' +import { mincReadImageNode } from '../../dist/index-node.js' import { FloatTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/mrc-test.js b/packages/image-io/typescript/test/node/mrc-test.js index 8113e9fc0..186f011d5 100644 --- a/packages/image-io/typescript/test/node/mrc-test.js +++ b/packages/image-io/typescript/test/node/mrc-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { mrcReadImageNode } from '../../dist/bundles/image-io-node.js' +import { mrcReadImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/nifti-test.js b/packages/image-io/typescript/test/node/nifti-test.js index d346837e6..1a34c892e 100644 --- a/packages/image-io/typescript/test/node/nifti-test.js +++ b/packages/image-io/typescript/test/node/nifti-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { niftiReadImageNode, niftiWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { niftiReadImageNode, niftiWriteImageNode } from '../../dist/index-node.js' import { FloatTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/nrrd-test.js b/packages/image-io/typescript/test/node/nrrd-test.js index 13fa4db87..e842f2f15 100644 --- a/packages/image-io/typescript/test/node/nrrd-test.js +++ b/packages/image-io/typescript/test/node/nrrd-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { nrrdReadImageNode, nrrdWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { nrrdReadImageNode, nrrdWriteImageNode } from '../../dist/index-node.js' import { FloatTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/png-test.js b/packages/image-io/typescript/test/node/png-test.js index e022d36b7..41fbb144f 100644 --- a/packages/image-io/typescript/test/node/png-test.js +++ b/packages/image-io/typescript/test/node/png-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { pngReadImageNode, pngWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { pngReadImageNode, pngWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/read-image-node-test.js b/packages/image-io/typescript/test/node/read-image-node-test.js index 7a8f0b910..280deef7d 100644 --- a/packages/image-io/typescript/test/node/read-image-node-test.js +++ b/packages/image-io/typescript/test/node/read-image-node-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { readImageNode } from '../../dist/bundles/image-io-node.js' +import { readImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/scanco-test.js b/packages/image-io/typescript/test/node/scanco-test.js index 8e628c44d..f4253c218 100644 --- a/packages/image-io/typescript/test/node/scanco-test.js +++ b/packages/image-io/typescript/test/node/scanco-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { scancoReadImageNode, scancoWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { scancoReadImageNode, scancoWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/tiff-test.js b/packages/image-io/typescript/test/node/tiff-test.js index 9c462fa09..a222781c2 100644 --- a/packages/image-io/typescript/test/node/tiff-test.js +++ b/packages/image-io/typescript/test/node/tiff-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { tiffReadImageNode, tiffWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { tiffReadImageNode, tiffWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/vtk-test.js b/packages/image-io/typescript/test/node/vtk-test.js index 71adc576e..d2493858d 100644 --- a/packages/image-io/typescript/test/node/vtk-test.js +++ b/packages/image-io/typescript/test/node/vtk-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { vtkReadImageNode, vtkWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { vtkReadImageNode, vtkWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/wasm-test.js b/packages/image-io/typescript/test/node/wasm-test.js index 5aa5e645a..bba6f2396 100644 --- a/packages/image-io/typescript/test/node/wasm-test.js +++ b/packages/image-io/typescript/test/node/wasm-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { wasmReadImageNode, wasmWriteImageNode } from '../../dist/bundles/image-io-node.js' +import { wasmReadImageNode, wasmWriteImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/test/node/write-image-node-test.js b/packages/image-io/typescript/test/node/write-image-node-test.js index da81f5e8d..d7550562e 100644 --- a/packages/image-io/typescript/test/node/write-image-node-test.js +++ b/packages/image-io/typescript/test/node/write-image-node-test.js @@ -1,7 +1,7 @@ import test from 'ava' import path from 'path' -import { readImageNode, writeImageNode } from '../../dist/bundles/image-io-node.js' +import { readImageNode, writeImageNode } from '../../dist/index-node.js' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' import { testInputPath, testOutputPath } from './common.js' diff --git a/packages/image-io/typescript/tsconfig.json b/packages/image-io/typescript/tsconfig.json index 9864b8178..242f02a0c 100644 --- a/packages/image-io/typescript/tsconfig.json +++ b/packages/image-io/typescript/tsconfig.json @@ -16,9 +16,10 @@ "noImplicitReturns": true, "skipLibCheck": true, "declaration": true, - "emitDeclarationOnly": true, - "declarationDir": "dist/" + "emitDeclarationOnly": false, + "outDir": "dist/", + "rootDir": "src/" }, "include": ["src/*.ts"], - "exclude": ["src/index-worker-embedded.ts"] + "exclude": ["src/index-worker-embedded*.ts"] } diff --git a/src/bindgen/python/emscripten/emscripten-pyodide-module.js b/src/bindgen/python/emscripten/emscripten-pyodide-module.js index a045e29d4..524becd98 100644 --- a/src/bindgen/python/emscripten/emscripten-pyodide-module.js +++ b/src/bindgen/python/emscripten/emscripten-pyodide-module.js @@ -6,7 +6,7 @@ function emscriptenPyodideModule(packageDir, pypackage, options) { const defaultJsModuleName = options.packageName.replace('itkwasm-', '') const version = options.packageVersion ?? '0.1.0' - const moduleUrl = options.jsModuleUrl ?? `https://cdn.jsdelivr.net/npm/${defaultJsPackageName}@{__version__}/dist/bundles/${defaultJsModuleName}.js` + const moduleUrl = options.jsModuleUrl ?? `https://cdn.jsdelivr.net/npm/${defaultJsPackageName}@{__version__}/dist/index.js` const moduleContent = `from itkwasm.pyodide import JsPackageConfig, JsPackage diff --git a/src/bindgen/typescript/demo/input-parameters-demo-typescript.js b/src/bindgen/typescript/demo/input-parameters-demo-typescript.js index eeeaf7f3a..dbce7cda1 100644 --- a/src/bindgen/typescript/demo/input-parameters-demo-typescript.js +++ b/src/bindgen/typescript/demo/input-parameters-demo-typescript.js @@ -106,14 +106,14 @@ function inputParametersDemoTypeScript(functionName, indent, parameter, required result += `${indent}${indent}details.innerHTML = \`
$\{globalThis.escapeHtml(JSON.stringify(model.${modelProperty}.get("${parameterName}"), globalThis.interfaceTypeJsonReplacer, 2))}
\`\n` } else if (parameterType === 'INPUT_IMAGE') { if (parameter.itemsExpectedMax > 1) { - result += `${indent}${indent}const readImages = await Promise.all(Array.from(files).map(async (file) => readImageFile(null, file)))\n` + result += `${indent}${indent}const readImages = await Promise.all(Array.from(files).map(async (file) => readImage(null, file)))\n` result += `${indent}${indent}readImages.forEach(img => img.webWorker.terminate())\n` result += `${indent}${indent}const inputImages = readImages.map(img => img.image)\n` result += `${indent}${indent}model.${modelProperty}.set("${parameterName}", inputImages)\n` result += `${indent}${indent}const details = document.getElementById("${functionName}-${parameter.name}-details")\n` result += `${indent}${indent}details.innerHTML = \`
$\{globalThis.escapeHtml(JSON.stringify(inputImages, globalThis.interfaceTypeJsonReplacer, 2))}
\`\n` } else { - result += `${indent}${indent}const { image, webWorker } = await readImageFile(null, files[0])\n` + result += `${indent}${indent}const { image, webWorker } = await readImage(null, files[0])\n` result += `${indent}${indent}webWorker.terminate()\n` result += `${indent}${indent}model.${modelProperty}.set("${parameterName}", image)\n` result += `${indent}${indent}const details = document.getElementById("${functionName}-${parameter.name}-details")\n` diff --git a/src/bindgen/typescript/demo/interface-functions-demo-typescript.js b/src/bindgen/typescript/demo/interface-functions-demo-typescript.js index bf4d4624e..d224d14e8 100644 --- a/src/bindgen/typescript/demo/interface-functions-demo-typescript.js +++ b/src/bindgen/typescript/demo/interface-functions-demo-typescript.js @@ -7,7 +7,7 @@ import packageToBundleName from "../package-to-bundle-name.js" import writeIfOverrideNotPresent from "../../write-if-override-not-present.js" import outputDemoRunTypeScript from './output-demo-run-typescript.js' import outputDemoTypeScript from './output-demo-typescript.js' -import interfaceJsonTypeToInterfaceType from '../../interface-json-type-to-interface-type.js' +import ioPackagesNeeded from './io-packages-needed.js' function interfaceFunctionsDemoTypeScript(packageName, interfaceJson, outputPath) { let result = '' @@ -16,32 +16,24 @@ function interfaceFunctionsDemoTypeScript(packageName, interfaceJson, outputPath const functionName = camelCase(interfaceJson.name) const functionNamePascalCase = pascalCase(interfaceJson.name) - let needReadMesh = false - let needReadImage = false - const pipelineComponents = ['inputs', 'parameters'] - pipelineComponents.forEach((pipelineComponent) => { - needReadMesh = needReadMesh || interfaceJson[pipelineComponent].filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Mesh').length > 0 - needReadImage = needReadImage || interfaceJson[pipelineComponent].filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Image').length > 0 - }) + const { needReadImage, needReadMesh, needWriteImage, needWriteMesh } = ioPackagesNeeded(interfaceJson) if (needReadMesh) { result += `import { readMeshFile } from 'itk-wasm'\n` } if (needReadImage) { - result += `import { readImageFile } from 'itk-wasm'\n` + result += `import { readImage } from '@itk-wasm/image-io'\n` } - const needWriteMesh = interfaceJson.outputs.filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Mesh').length > 0 if (needWriteMesh) { result += `import { writeMeshArrayBuffer } from 'itk-wasm'\n` } - const needWriteImage = interfaceJson.outputs.filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Image').length > 0 if (needWriteImage) { - result += `import { writeImageArrayBuffer } from 'itk-wasm'\n` + result += `import { writeImage } from '@itk-wasm/image-io'\n` } if (needReadImage || needWriteImage) { result += `import { copyImage } from 'itk-wasm'\n` } - result += `import * as ${camelCase(bundleName)} from '../../../dist/bundles/${bundleName}.js'\n` + result += `import * as ${camelCase(bundleName)} from '../../../dist/index.js'\n` result += `import ${functionName}LoadSampleInputs, { usePreRun } from "./${interfaceJson.name}-load-sample-inputs.js"\n` const loadSampleInputsModulePath = path.join(outputPath, `${interfaceJson.name}-load-sample-inputs.ts`) diff --git a/src/bindgen/typescript/demo/io-packages-needed.js b/src/bindgen/typescript/demo/io-packages-needed.js new file mode 100644 index 000000000..4349025f1 --- /dev/null +++ b/src/bindgen/typescript/demo/io-packages-needed.js @@ -0,0 +1,16 @@ +import interfaceJsonTypeToInterfaceType from "../../interface-json-type-to-interface-type.js" + +function ioPackagesNeeded(interfaceJson) { + let needReadMesh = false + let needReadImage = false + const pipelineComponents = ['inputs', 'parameters'] + pipelineComponents.forEach((pipelineComponent) => { + needReadMesh = needReadMesh || interfaceJson[pipelineComponent].filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Mesh').length > 0 + needReadImage = needReadImage || interfaceJson[pipelineComponent].filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Image').length > 0 + }) + const needWriteMesh = interfaceJson.outputs.filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Mesh').length > 0 + const needWriteImage = interfaceJson.outputs.filter((value) => interfaceJsonTypeToInterfaceType.get(value.type) === 'Image').length > 0 + return { needReadImage, needReadMesh, needWriteImage, needWriteMesh} +} + +export default ioPackagesNeeded diff --git a/src/bindgen/typescript/demo/output-demo-typescript.js b/src/bindgen/typescript/demo/output-demo-typescript.js index c2fbfcb15..d6d73c816 100644 --- a/src/bindgen/typescript/demo/output-demo-typescript.js +++ b/src/bindgen/typescript/demo/output-demo-typescript.js @@ -65,9 +65,9 @@ function outputDemoTypeScript(functionName, prefix, indent, parameter) { result += `${prefix}${indent}${indent}${indent}const ${parameterName}DownloadFormat = document.getElementById('${parameter.name}-output-format')\n` result += `${prefix}${indent}${indent}${indent}const downloadFormat = ${parameterName}DownloadFormat.value || 'nrrd'\n` result += `${prefix}${indent}${indent}${indent}const fileName = \`${parameterName}.\${downloadFormat}\`\n` - result += `${prefix}${indent}${indent}${indent}const { webWorker, arrayBuffer } = await writeImageArrayBuffer(null, copyImage(model.outputs.get("${parameterName}")), fileName)\n\n` + result += `${prefix}${indent}${indent}${indent}const { webWorker, serializedImage } = await writeImage(null, copyImage(model.outputs.get("${parameterName}")), fileName)\n\n` result += `${prefix}${indent}${indent}${indent}webWorker.terminate()\n` - result += `${prefix}${indent}${indent}${indent}globalThis.downloadFile(arrayBuffer, fileName)\n` + result += `${prefix}${indent}${indent}${indent}globalThis.downloadFile(serializedImage, fileName)\n` result += `${prefix}${indent}${indent}}\n` result += `${prefix}${indent}})\n` break diff --git a/src/bindgen/typescript/function-module.js b/src/bindgen/typescript/function-module.js index 40103a1f7..9dabbbbb4 100644 --- a/src/bindgen/typescript/function-module.js +++ b/src/bindgen/typescript/function-module.js @@ -70,14 +70,17 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, } functionContent += `import ${modulePascalCase}${nodeTextCamel}Result from './${moduleKebabCase}${nodeTextKebab}-result.js'\n\n` if (forNode) { - functionContent += "\nimport path from 'path'\n\n" + functionContent += "import path from 'path'\n\n" } else { - functionContent += "\nimport { getPipelinesBaseUrl } from './pipelines-base-url.js'" - functionContent += "\nimport { getPipelineWorkerUrl } from './pipeline-worker-url.js'\n\n" + functionContent += "import { getPipelinesBaseUrl } from './pipelines-base-url.js'\n" + functionContent += "import { getPipelineWorkerUrl } from './pipeline-worker-url.js'\n\n" } const readmeParametersTable = [['Parameter', 'Type', 'Description'],] functionContent += `/**\n * ${interfaceJson.description}\n *\n` + if (!forNode) { + readmeParametersTable.push(['`webWorker`', '*null or Worker or boolean*', 'WebWorker to use for computation. Set to null to create a new worker. Or, pass an existing worker. Or, set to `false` to run in the current thread / worker.']) + } interfaceJson.inputs.forEach((input) => { if (!interfaceJsonTypeToTypeScriptType.has(input.type)) { console.error(`Unexpected input type: ${input.type}`) @@ -103,7 +106,7 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, const isArray = output.itemsExpectedMax > 1 ? '[]' : '' const typescriptType = `string${isArray}` functionContent += ` * @param {${typescriptType}} ${camelCase(output.name)} - ${output.description}\n` - readmeParametersTable.push([`\`${camelCase(output.name)}\``, `*${typescriptType}*`, output.description]) + readmeParametersTable.push([`\`${camelCase(output.name)}\``, `*${typescriptType.replaceAll('|', 'or')}*`, output.description]) }) if (haveOptions) { @@ -116,7 +119,7 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, let functionCall = '' functionCall += `async function ${moduleCamelCase}${nodeTextCamel}(\n` if (!forNode) { - functionCall += ' webWorker: null | Worker,\n' + functionCall += ' webWorker: null | Worker | boolean,\n' } interfaceJson.inputs.forEach((input, index) => { let typescriptType = interfaceJsonTypeToTypeScriptType.get(input.type) @@ -447,7 +450,7 @@ function functionModule (srcOutputDir, forNode, interfaceJson, modulePascalCase, const outputsVar = interfaceJson.outputs.filter(o => !o.type.includes('FILE') || !forNode).length ? ' outputs\n' : '' if (forNode) { - functionContent += `\n const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', '${moduleKebabCase}')\n\n` + functionContent += `\n const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', '${moduleKebabCase}')\n\n` const mountDirsArg = needMountDirs ? ', mountDirs' : '' functionContent += ` const {\n returnValue,\n stderr,\n${outputsVar} } = await runPipelineNode(pipelinePath, args, desiredOutputs, inputs${mountDirsArg})\n` } else { diff --git a/src/bindgen/typescript/resources/demo-app/index.ts b/src/bindgen/typescript/resources/demo-app/index.ts index be94c4c53..2f7082765 100644 --- a/src/bindgen/typescript/resources/demo-app/index.ts +++ b/src/bindgen/typescript/resources/demo-app/index.ts @@ -1,9 +1,7 @@ -import * as @bindgenBundleNameCamelCase@ from '../../../dist/bundles/@bindgenBundleName@.js' +import * as @bindgenBundleNameCamelCase@ from '../../../dist/index.js' // Use local, vendored WebAssembly module assets const pipelinesBaseUrl: string | URL = new URL('/pipelines', document.location.origin).href @bindgenBundleNameCamelCase@.setPipelinesBaseUrl(pipelinesBaseUrl) -const pipelineWorkerUrl: string | URL | null = new URL('/web-workers/itk-wasm-pipeline.worker.js', document.location.origin).href -@bindgenBundleNameCamelCase@.setPipelineWorkerUrl(pipelineWorkerUrl) -@bindgenFunctionLogic@ \ No newline at end of file +@bindgenFunctionLogic@ diff --git a/src/bindgen/typescript/resources/itkConfig.js b/src/bindgen/typescript/resources/itkConfig.js deleted file mode 100644 index be9beaf3f..000000000 --- a/src/bindgen/typescript/resources/itkConfig.js +++ /dev/null @@ -1,11 +0,0 @@ -import version from 'itk-wasm' - -const itkConfig = { - // Use the worker bundled by vite or webpack - pipelineWorkerUrl: null, - imageIOUrl: `https://cdn.jsdelivr.net/npm/itk-image-io@${version}`, - meshIOUrl: `https://cdn.jsdelivr.net/npm/itk-mesh-io@${version}`, - pipelinesUrl: '/pipelines' -} - -export default itkConfig diff --git a/src/bindgen/typescript/resources/pipeline-worker-url.ts b/src/bindgen/typescript/resources/pipeline-worker-url.ts index e1125290c..39118ba4a 100644 --- a/src/bindgen/typescript/resources/pipeline-worker-url.ts +++ b/src/bindgen/typescript/resources/pipeline-worker-url.ts @@ -1,8 +1,8 @@ import { getPipelineWorkerUrl as itkWasmGetPipelineWorkerUrl } from 'itk-wasm' -import packageJson from '../package.json' let pipelineWorkerUrl: string | URL | null | undefined -const defaultPipelineWorkerUrl = `https://cdn.jsdelivr.net/npm/@${packageJson.version}/dist/web-workers/itk-wasm-pipeline.worker.js` +// Use the version shipped with an app's bundler +const defaultPipelineWorkerUrl = null export function setPipelineWorkerUrl (workerUrl: string | URL | null): void { pipelineWorkerUrl = workerUrl diff --git a/src/bindgen/typescript/resources/rollup.browser.config.js b/src/bindgen/typescript/resources/rollup.browser.config.js index 48b48bf35..69f809a75 100644 --- a/src/bindgen/typescript/resources/rollup.browser.config.js +++ b/src/bindgen/typescript/resources/rollup.browser.config.js @@ -1,5 +1,4 @@ import { nodeResolve } from '@rollup/plugin-node-resolve' -import copy from 'rollup-plugin-copy' import typescript from '@rollup/plugin-typescript' import commonjs from '@rollup/plugin-commonjs' import nodePolyfills from 'rollup-plugin-polyfill-node' @@ -9,7 +8,6 @@ import packageJson from '../package.json' assert { type: 'json' } import json from '@rollup/plugin-json' import path from 'path' -const itkConfig = './src/itkConfig.js' const bundleName = path.basename(packageJson.name) export default { @@ -41,11 +39,4 @@ export default { typescript(), json(), ], - resolve: { - // where itk-wasm code has 'import ../itkConfig.js` point to the path of itkConfig - alias: { - '../itkConfig.js': itkConfig, - '../../itkConfig.js': itkConfig - } - } } diff --git a/src/bindgen/typescript/resources/template.package.json b/src/bindgen/typescript/resources/template.package.json index 56c6aff44..0e8926fbc 100644 --- a/src/bindgen/typescript/resources/template.package.json +++ b/src/bindgen/typescript/resources/template.package.json @@ -4,12 +4,12 @@ "description": "", "type": "module", "module": "./dist/bundles/bundle-name.js", - "types": "./dist/src/index.d.ts", + "types": "./dist/index.d.ts", "exports": { ".": { - "types": "./dist/src/index.d.ts", - "browser": "./dist/bundles/bundle-name.js", - "node": "./dist/bundles/bundle-name-node.js", + "types": "./dist/index.d.ts", + "browser": "./dist/bundle-name.js", + "node": "./dist/bundle-name-node.js", "default": "./dist/bundles/bundle-name.js" } }, @@ -17,8 +17,9 @@ "start": "npm run copyShoelaceAssets && vite -c build/vite.config.js", "test": "echo \"Error: no test specified\" && exit 1", "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", - "build:node": "rollup -c ./build/rollup.node.config.js", - "build:browser": "rollup -c ./build/rollup.browser.config.js", + "build:node": "esbuild --bundle --format=esm --banner:js=\"import { createRequire } from 'module';const require = createRequire(import.meta.url);\" --platform=node --outfile=./dist/index-node.js ./src/index-node.ts", + "build:browser": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/ && esbuild --bundle --format=esm --outfile=./dist/index.js ./src/index.ts", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/index-worker-embedded.js ./src/index-worker-embedded.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" @@ -32,26 +33,16 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.138" + "itk-wasm": "^1.0.0-b.152" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.0", - "@rollup/plugin-typescript": "^11.1.1", + "@itk-wasm/image-io": "^0.2.0", "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", - "debug": "^4.3.4", - "rollup": "^3.9.0", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-ignore": "^1.0.10", - "rollup-plugin-polyfill-node": "^0.12.0", + "esbuild": "^0.19.5", "shx": "^0.3.4", - "supports-color": "^9.3.1", - "tslib": "^2.5.2", "typescript": "^5.0.4", - "vite": "^4.3.3", - "vite-plugin-static-copy": "^0.14.0" + "vite": "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" } } diff --git a/src/bindgen/typescript/resources/tsconfig.json b/src/bindgen/typescript/resources/tsconfig.json index 4eba4b8ec..242f02a0c 100644 --- a/src/bindgen/typescript/resources/tsconfig.json +++ b/src/bindgen/typescript/resources/tsconfig.json @@ -16,8 +16,10 @@ "noImplicitReturns": true, "skipLibCheck": true, "declaration": true, - "emitDeclarationOnly": true, - "declarationDir": "dist/" + "emitDeclarationOnly": false, + "outDir": "dist/", + "rootDir": "src/" }, - "include": ["src/*.ts"] + "include": ["src/*.ts"], + "exclude": ["src/index-worker-embedded*.ts"] } diff --git a/src/bindgen/typescript/resources/vite.config.js b/src/bindgen/typescript/resources/vite.config.js index 3157a9ded..38df171ce 100644 --- a/src/bindgen/typescript/resources/vite.config.js +++ b/src/bindgen/typescript/resources/vite.config.js @@ -8,12 +8,18 @@ export default defineConfig({ outDir: '../../../demo-app', emptyOutDir: true, }, + worker: { + format: 'es' + }, + optimizeDeps: { + exclude: ['@itk-wasm/image-io'] + }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../dist/core/web-workers/*', dest: 'web-workers' }, + { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm.zst}', dest: 'pipelines' }, ], }) ], diff --git a/src/bindgen/typescript/results-module.js b/src/bindgen/typescript/results-module.js index e920a8220..a7b37910b 100644 --- a/src/bindgen/typescript/results-module.js +++ b/src/bindgen/typescript/results-module.js @@ -15,7 +15,7 @@ function resultsModule (srcOutputDir, interfaceJson, forNode, modulePascalCase, readmeResult += `\n**\`${modulePascalCase}${nodeTextCamel}Result\` interface:**\n\n` if (!forNode) { resultContent += ' /** WebWorker used for computation */\n webWorker: Worker | null\n\n' - readmeResultTable.push(['**webWorker**', '*Worker*', 'WebWorker used for computation']) + readmeResultTable.push(['`webWorker`', '*Worker*', 'WebWorker used for computation.']) } // track unique output types in this set diff --git a/src/bindgen/typescript/typescript-bindgen.js b/src/bindgen/typescript/typescript-bindgen.js index a9ca2e361..f3b004616 100644 --- a/src/bindgen/typescript/typescript-bindgen.js +++ b/src/bindgen/typescript/typescript-bindgen.js @@ -42,23 +42,6 @@ function setPipelinesBaseUrl( function getPipelinesBaseUrl() : string | URL \`\`\` -#### setPipelineWorkerUrl - -*Set base URL for the itk-wasm pipeline worker script when vendored.* - -\`\`\`ts -function setPipelineWorkerUrl( - baseUrl: string | URL -) : void -\`\`\` - -#### getPipelineWorkerUrl - -*Get base URL for the itk-wasm pipeline worker script when vendored.* - -\`\`\`ts -function getPipelineWorkerUrl() : string | URL -\`\`\` ` readmeNodeInterface += typescriptBindings(outputDir, buildDir, emscriptenWasmBinaries, options, true) readme += readmeUsage diff --git a/src/bindgen/typescript/typescript-bindings.js b/src/bindgen/typescript/typescript-bindings.js index e06ca80d2..4bc1bf564 100644 --- a/src/bindgen/typescript/typescript-bindings.js +++ b/src/bindgen/typescript/typescript-bindings.js @@ -50,10 +50,10 @@ function typescriptBindings (outputDir, buildDir, wasmBinaries, options, forNode const packageJson = JSON.parse(fs.readFileSync(bindgenResource('template.package.json'))) packageJson.name = packageName packageJson.description = options.packageDescription - packageJson.module = `./dist/bundles/${bundleName}.js` - packageJson.exports['.'].browser = `./dist/bundles/${bundleName}.js` - packageJson.exports['.'].node = `./dist/bundles/${bundleName}-node.js` - packageJson.exports['.'].default = `./dist/bundles/${bundleName}.js` + packageJson.module = `./dist/index.js` + packageJson.exports['.'].browser = `./dist/index.js` + packageJson.exports['.'].node = `./dist/index-node.js` + packageJson.exports['.'].default = `./dist/index.js` if (options.repository) { packageJson.repository = { 'type': 'git', 'url': options.repository } } @@ -73,7 +73,6 @@ function typescriptBindings (outputDir, buildDir, wasmBinaries, options, forNode if (!forNode) { indexContent += "export * from './pipelines-base-url.js'\n" - indexContent += "export * from './pipeline-worker-url.js'\n" } writeSupportFiles(outputDir, forNode, bindgenResource, packageName, options.packageDescription) @@ -160,19 +159,14 @@ if (!params.has('functionName')) { allUsedInterfaceTypes.forEach(iType => indexContent += `export type { ${iType} } from 'itk-wasm'\n`) } - readmeInterface += ` setPipelinesBaseUrl, + if (!forNode) { + readmeInterface += ` setPipelinesBaseUrl, getPipelinesBaseUrl, - setPipelineWorkerUrl, - getPipelineWorkerUrl, ` + } readmeInterface += `} from "${packageName}"\n\`\`\`\n` readmeInterface += readmePipelines - const itkConfigPath = path.join(outputDir, 'src', 'itkConfig.js') - if (!fs.existsSync(itkConfigPath)) { - fs.copyFileSync(bindgenResource('itkConfig.js'), itkConfigPath) - } - const indexPath = path.join(srcOutputDir, `index${nodeTextKebab}.ts`) writeIfOverrideNotPresent(indexPath, indexContent) diff --git a/src/core/createWebWorkerPromise.ts b/src/core/createWebWorkerPromise.ts index f7c4e782d..d35e7999c 100644 --- a/src/core/createWebWorkerPromise.ts +++ b/src/core/createWebWorkerPromise.ts @@ -15,7 +15,7 @@ interface itkWorker extends Worker { // Internal function to create a web worker promise async function createWebWorkerPromise (existingWorker: Worker | null, pipelineWorkerUrl?: string | null): Promise { let workerPromise: typeof WebworkerPromise - if (existingWorker != null) { + if (existingWorker !== null) { // See if we have a worker promise attached the worker, if so reuse it. This ensures // that we can safely reuse the worker without issues. const itkWebWorker = existingWorker as itkWorker diff --git a/src/core/internal/loadEmscriptenModuleWebWorker.ts b/src/core/internal/loadEmscriptenModuleWebWorker.ts index 48dabd000..ca5ff89c2 100644 --- a/src/core/internal/loadEmscriptenModuleWebWorker.ts +++ b/src/core/internal/loadEmscriptenModuleWebWorker.ts @@ -5,11 +5,10 @@ const decoder = new ZSTDDecoder() let decoderInitialized = false import ITKWasmEmscriptenModule from '../ITKWasmEmscriptenModule.js' -import camelCase from './camelCase.js' // Load the Emscripten module in the browser in a WebWorker. // -// baseUrl is usually taken from '../itkConfig.js', but a different value +// baseUrl is usually taken from 'getPipelinesBaseUrl()', but a different value // could be passed. async function loadEmscriptenModuleWebWorker(moduleRelativePathOrURL: string | URL, baseUrl: string): Promise { let modulePrefix = null From 84e78df94d31986e42f9f16162eef2370153fbe2 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sat, 4 Nov 2023 17:50:28 -0400 Subject: [PATCH 14/23] fix(bindgen): remove rollup configurations Replaced by tsc. --- .../resources/rollup.browser.config.js | 42 ------------------- .../resources/rollup.node.config.js | 32 -------------- src/bindgen/typescript/write-support-files.js | 10 ----- 3 files changed, 84 deletions(-) delete mode 100644 src/bindgen/typescript/resources/rollup.browser.config.js delete mode 100644 src/bindgen/typescript/resources/rollup.node.config.js diff --git a/src/bindgen/typescript/resources/rollup.browser.config.js b/src/bindgen/typescript/resources/rollup.browser.config.js deleted file mode 100644 index 69f809a75..000000000 --- a/src/bindgen/typescript/resources/rollup.browser.config.js +++ /dev/null @@ -1,42 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import nodePolyfills from 'rollup-plugin-polyfill-node' -import ignore from 'rollup-plugin-ignore' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import json from '@rollup/plugin-json' -import path from 'path' - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index.ts', - output: [ - { - file: `./dist/bundles/${bundleName}.js`, - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - plugins: [ - copy({ - targets: [ - { src: 'node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js', dest: 'dist/web-workers/' }, - ], - hook: 'writeBundle' - }), - ignore(['crypto']), - nodeResolve({ - preferBuiltins: false, - browser: true, - }), - commonjs({ - transformMixedEsModules: true - }), - nodePolyfills(), - typescript(), - json(), - ], -} diff --git a/src/bindgen/typescript/resources/rollup.node.config.js b/src/bindgen/typescript/resources/rollup.node.config.js deleted file mode 100644 index 431b29d3e..000000000 --- a/src/bindgen/typescript/resources/rollup.node.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import path from 'path' - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index-node.ts', - output: [ - { - file: `./dist/bundles/${bundleName}-node.js`, - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - plugins: [ - commonjs({ - transformMixedEsModules: true - }), - nodeResolve({ - preferBuiltins: true, - browser: false, - }), - typescript(), - json(), - ], -} diff --git a/src/bindgen/typescript/write-support-files.js b/src/bindgen/typescript/write-support-files.js index 7423cb9dd..6a72de106 100644 --- a/src/bindgen/typescript/write-support-files.js +++ b/src/bindgen/typescript/write-support-files.js @@ -61,20 +61,10 @@ function writeSupportFiles(outputDir, forNode, bindgenResource, packageName, pac const demoJsUtilities = path.join(outputDir, 'test', 'browser', 'demo-app', 'utilities.js') writeIfOverrideNotPresent(demoJsUtilities, fs.readFileSync(bindgenResource(path.join('demo-app', 'utilities.js')), { encoding: 'utf8', flag: 'r' })) - const rollupConfigPath = path.join(outputDir, 'build', 'rollup.browser.config.js') - if (!fs.existsSync(rollupConfigPath)) { - fs.copyFileSync(bindgenResource('rollup.browser.config.js'), rollupConfigPath) - } - const viteConfigPath = path.join(outputDir, 'build', 'vite.config.js') if (!fs.existsSync(viteConfigPath)) { fs.copyFileSync(bindgenResource('vite.config.js'), viteConfigPath) } - } else { - const rollupConfigPath = path.join(outputDir, 'build', 'rollup.node.config.js') - if (!fs.existsSync(rollupConfigPath)) { - fs.copyFileSync(bindgenResource('rollup.node.config.js'), rollupConfigPath) - } } const tsConfigPath = path.join(outputDir, 'tsconfig.json') From f46df272e5a24516e129d5b59e6a8a8f1f1edf99 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sat, 4 Nov 2023 17:52:21 -0400 Subject: [PATCH 15/23] feat(bindgen): embed js module bundle in the python package Module with embedded with WebWorker. --- .../python/emscripten/emscripten-package.js | 2 +- .../emscripten/emscripten-pyodide-module.js | 23 +++++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/bindgen/python/emscripten/emscripten-package.js b/src/bindgen/python/emscripten/emscripten-package.js index 5a5b83c13..4b2b04c63 100644 --- a/src/bindgen/python/emscripten/emscripten-package.js +++ b/src/bindgen/python/emscripten/emscripten-package.js @@ -28,7 +28,7 @@ function emscriptenPackage(outputDir, buildDir, wasmBinaries, options) { const async = true const sync = false packageDunderInit(outputDir, buildDir, wasmBinaries, packageName, packageDescription, packageDir, pypackage, async, sync) - emscriptenPyodideModule(packageDir, pypackage, options) + emscriptenPyodideModule(outputDir, packageDir, pypackage, options) emscriptenTestModule(packageDir, pypackage) const wasmModulesDir = path.join(packageDir, pypackage, 'wasm_modules') diff --git a/src/bindgen/python/emscripten/emscripten-pyodide-module.js b/src/bindgen/python/emscripten/emscripten-pyodide-module.js index 524becd98..59e0a9629 100644 --- a/src/bindgen/python/emscripten/emscripten-pyodide-module.js +++ b/src/bindgen/python/emscripten/emscripten-pyodide-module.js @@ -1,26 +1,29 @@ import fs from 'fs-extra' import path from 'path' -function emscriptenPyodideModule(packageDir, pypackage, options) { - const defaultJsPackageName = options.packageName.replace('itkwasm-', '@itk-wasm/') - const defaultJsModuleName = options.packageName.replace('itkwasm-', '') - const version = options.packageVersion ?? '0.1.0' +import writeIfOverrideNotPresent from '../../write-if-override-not-present.js' - const moduleUrl = options.jsModuleUrl ?? `https://cdn.jsdelivr.net/npm/${defaultJsPackageName}@{__version__}/dist/index.js` +function emscriptenPyodideModule(outputDir, packageDir, pypackage, options) { + const defaultJsModuleName = options.packageName.replace('itkwasm-', '') + const defaultJsModulePath = path.join(outputDir, '..', 'typescript', 'dist', `${defaultJsModuleName}-worker-embedded.js`) + const moduleUrl = options.jsModulePath ?? defaultJsModulePath + if (!fs.existsSync(moduleUrl)) { + console.error(`Could not find ${moduleUrl}`) + process.exit(1) + } + const jsModuleContent = fs.readFileSync(moduleUrl, { encoding: 'utf8', flag: 'r' }) const moduleContent = `from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ - -default_config = JsPackageConfig(f"${moduleUrl}") +default_js_module = """data:text/javascript;charset=utf-8,${jsModuleContent}""" +default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) ` const modulePath = path.join(packageDir, pypackage, 'js_package.py') - if (!fs.existsSync(modulePath)) { - fs.writeFileSync(modulePath, moduleContent) - } + writeIfOverrideNotPresent(modulePath, moduleContent, '#') } export default emscriptenPyodideModule From 8f73d22bfb7aa191b957e351becfb8fdaea6f257 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sat, 4 Nov 2023 17:58:14 -0400 Subject: [PATCH 16/23] feat(image-io): add itkwasm-image-io-emscripten package --- package.json | 4 +- .../itkwasm-image-io-emscripten/README.md | 23 + .../itkwasm_image_io_emscripten/__init__.py | 7 + .../itkwasm_image_io_emscripten/_version.py | 1 + .../itkwasm_image_io_emscripten/js_package.py | 5891 +++++++++++++++++ .../pyproject.toml | 72 + .../test/__init__.py | 0 .../test/test_itkwasm_image_io.py | 20 + .../itkwasm_image_io_wasi/_version.py | 2 +- .../itkwasm_image_io_wasi/read_image.py | 1 - .../itkwasm_image_io/_version.py | 2 +- packages/image-io/typescript/README.md | 4 +- packages/image-io/typescript/package.json | 2 +- 13 files changed, 6021 insertions(+), 8 deletions(-) create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/README.md create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/test/__init__.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/test/test_itkwasm_image_io.py diff --git a/package.json b/package.json index 84135be75..3f035fa9f 100644 --- a/package.json +++ b/package.json @@ -48,8 +48,8 @@ "build:bindgen:typescript:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build bindgen --package-version 3.0.1 --package-name @itk-wasm/compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:bindgen:python:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b wasi-build bindgen --package-version 3.0.1 --interface python --package-name itkwasm-compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:image-io": "node ./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build build", - "build:bindgen:typescript:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build bindgen --package-version 0.3.0 --package-name @itk-wasm/image-io --package-description \"Input and output for scientific and medical image file formats.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b wasi-build bindgen --interface python --package-name itkwasm-image-io --package-description \"Input and output for scientific and medical image file formats.\" --package-version 0.3.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build bindgen --package-version 0.4.0 --package-name @itk-wasm/image-io --package-description \"Input and output for scientific and medical image file formats.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b wasi-build bindgen --interface python --package-name itkwasm-image-io --package-description \"Input and output for scientific and medical image file formats.\" --package-version 0.4.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:packages": "npm run build:emscripten:compress-stringify && npm run build:bindgen:typescript:compress-stringify && npm run build:emscripten:dicom && npm run build:bindgen:typescript:dicom && npm run build:emscripten:compare-images && npm run build:bindgen:typescript:compare-images && npm run build:emscripten:image-io && npm run build:bindgen:typescript:image-io", "build:wasi": "node ./src/build-wasi.js && npm run build:wasi:packages", "build:wasi:compress-stringify": "node ./src/itk-wasm-cli.js -i itkwasm/wasi:latest -s packages/compress-stringify -b wasi-build build", diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/README.md b/packages/image-io/python/itkwasm-image-io-emscripten/README.md new file mode 100644 index 000000000..e2139810d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/README.md @@ -0,0 +1,23 @@ +# itkwasm-image-io-emscripten + +[![PyPI version](https://badge.fury.io/py/itkwasm-image-io-emscripten.svg)](https://badge.fury.io/py/itkwasm-image-io-emscripten) + +Input and output for scientific and medical image file formats. Emscripten implementation. + +This package provides the Emscripten WebAssembly implementation. It is usually not called directly. Please use the [`itkwasm-image-io`](https://pypi.org/project/itkwasm-image-io/) instead. + + +## Installation + +```sh +import micropip +await micropip.install('itkwasm-image-io-emscripten') +``` + +## Development + +```sh +pip install hatch +hatch run download-pyodide +hatch run test +``` diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py new file mode 100644 index 000000000..1370b2a2f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py @@ -0,0 +1,7 @@ +# Generated file. To retain edits, remove this comment. + +"""itkwasm-image-io-emscripten: Input and output for scientific and medical image file formats. Emscripten implementation.""" + + + +from ._version import __version__ diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py new file mode 100644 index 000000000..6a9beea82 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py @@ -0,0 +1 @@ +__version__ = "0.4.0" diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py new file mode 100644 index 000000000..a60736934 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py @@ -0,0 +1,5891 @@ +# Generated file. To retain edits, remove this comment. + +from itkwasm.pyodide import JsPackageConfig, JsPackage + +from ._version import __version__ +default_js_module = """data:text/javascript;charset=utf-8,var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __commonJS = (cb, mod) => function __require() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/tiny-emitter.js +var require_tiny_emitter = __commonJS({ + "node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/tiny-emitter.js"(exports, module) { + var TinyEmitter = class { + constructor() { + Object.defineProperty(this, "__listeners", { + value: {}, + enumerable: false, + writable: false + }); + } + emit(eventName, ...args) { + if (!this.__listeners[eventName]) + return this; + for (const handler of this.__listeners[eventName]) { + handler(...args); + } + return this; + } + once(eventName, handler) { + const once = (...args) => { + this.off(eventName, once); + handler(...args); + }; + return this.on(eventName, once); + } + on(eventName, handler) { + if (!this.__listeners[eventName]) + this.__listeners[eventName] = []; + this.__listeners[eventName].push(handler); + return this; + } + off(eventName, handler) { + if (handler) + this.__listeners[eventName] = this.__listeners[eventName].filter((h) => h !== handler); + else + this.__listeners[eventName] = []; + return this; + } + }; + module.exports = TinyEmitter; + } +}); + +// node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/index.js +var require_src = __commonJS({ + "node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/index.js"(exports, module) { + var TinyEmitter = require_tiny_emitter(); + var MESSAGE_RESULT = 0; + var MESSAGE_EVENT = 1; + var RESULT_SUCCESS = 1; + var Worker2 = class extends TinyEmitter { + /** + * + * @param worker {Worker} + */ + constructor(worker) { + super(); + this._messageId = 1; + this._messages = /* @__PURE__ */ new Map(); + this._worker = worker; + this._worker.onmessage = this._onMessage.bind(this); + this._id = Math.ceil(Math.random() * 1e7); + } + terminate() { + this._worker.terminate(); + } + /** + * return true if there is no unresolved jobs + * @returns {boolean} + */ + isFree() { + return this._messages.size === 0; + } + jobsLength() { + return this._messages.size; + } + /** + * @param operationName string + * @param data any + * @param transferable array + * @param onEvent function + * @returns {Promise} + */ + exec(operationName, data = null, transferable = [], onEvent) { + return new Promise((res, rej) => { + const messageId = this._messageId++; + this._messages.set(messageId, [res, rej, onEvent]); + this._worker.postMessage([messageId, data, operationName], transferable || []); + }); + } + /** + * + * @param data any + * @param transferable array + * @param onEvent function + * @returns {Promise} + */ + postMessage(data = null, transferable = [], onEvent) { + return new Promise((res, rej) => { + const messageId = this._messageId++; + this._messages.set(messageId, [res, rej, onEvent]); + this._worker.postMessage([messageId, data], transferable || []); + }); + } + emit(eventName, ...args) { + this._worker.postMessage({ eventName, args }); + } + _onMessage(e) { + if (!Array.isArray(e.data) && e.data.eventName) { + return super.emit(e.data.eventName, ...e.data.args); + } + const [type, ...args] = e.data; + if (type === MESSAGE_EVENT) + this._onEvent(...args); + else if (type === MESSAGE_RESULT) + this._onResult(...args); + else + throw new Error(`Wrong message type '${type}'`); + } + _onResult(messageId, success, payload) { + const [res, rej] = this._messages.get(messageId); + this._messages.delete(messageId); + return success === RESULT_SUCCESS ? res(payload) : rej(payload); + } + _onEvent(messageId, eventName, data) { + const [, , onEvent] = this._messages.get(messageId); + if (onEvent) { + onEvent(eventName, data); + } + } + }; + module.exports = Worker2; + } +}); + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/version.js +var version = "1.0.0-b.152"; +var version_default = version; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/itkConfig.js +var itkConfig = { + pipelineWorkerUrl: `https://cdn.jsdelivr.net/npm/itk-wasm@${version_default}/dist/core/web-workers/bundles/pipeline.min.worker.js`, + imageIOUrl: `https://cdn.jsdelivr.net/npm/itk-image-io@${version_default}`, + meshIOUrl: `https://cdn.jsdelivr.net/npm/itk-mesh-io@${version_default}`, + pipelinesUrl: `https://cdn.jsdelivr.net/npm/itk-wasm@${version_default}/dist/pipelines` +}; +var itkConfig_default = itkConfig; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/InterfaceTypes.js +var InterfaceTypes = { + // Todo: remove Interface prefix after IOTypes has been removed + TextFile: "InterfaceTextFile", + BinaryFile: "InterfaceBinaryFile", + TextStream: "InterfaceTextStream", + BinaryStream: "InterfaceBinaryStream", + Image: "InterfaceImage", + Mesh: "InterfaceMesh", + PolyData: "InterfacePolyData", + JsonCompatible: "InterfaceJsonCompatible" +}; +var InterfaceTypes_default = InterfaceTypes; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/int-types.js +var IntTypes = { + Int8: "int8", + UInt8: "uint8", + Int16: "int16", + UInt16: "uint16", + Int32: "int32", + UInt32: "uint32", + Int64: "int64", + UInt64: "uint64", + SizeValueType: "uint64", + IdentifierType: "uint64", + IndexValueType: "int64", + OffsetValueType: "int64" +}; +var int_types_default = IntTypes; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/float-types.js +var FloatTypes = { + Float32: "float32", + Float64: "float64", + SpacePrecisionType: "float64" +}; +var float_types_default = FloatTypes; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/IOTypes.js +var IOTypes = { + Text: "Text", + Binary: "Binary", + Image: "Image", + Mesh: "Mesh" +}; +var IOTypes_default = IOTypes; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/pixel-types.js +var PixelTypes = { + Unknown: "Unknown", + Scalar: "Scalar", + RGB: "RGB", + RGBA: "RGBA", + Offset: "Offset", + Vector: "Vector", + Point: "Point", + CovariantVector: "CovariantVector", + SymmetricSecondRankTensor: "SymmetricSecondRankTensor", + DiffusionTensor3D: "DiffusionTensor3D", + Complex: "Complex", + FixedArray: "FixedArray", + Array: "Array", + Matrix: "Matrix", + VariableLengthVector: "VariableLengthVector", + VariableSizeMatrix: "VariableSizeMatrix" +}; +var pixel_types_default = PixelTypes; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/setMatrixElement.js +function setMatrixElement(matrixData, columns, row, column, value) { + matrixData[column + row * columns] = value; +} +var setMatrixElement_default = setMatrixElement; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/image-type.js +var ImageType = class { + constructor(dimension = 2, componentType = int_types_default.UInt8, pixelType = pixel_types_default.Scalar, components = 1) { + this.dimension = dimension; + this.componentType = componentType; + this.pixelType = pixelType; + this.components = components; + } +}; +var image_type_default = ImageType; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/image.js +var Image = class { + constructor(imageType = new image_type_default()) { + this.imageType = imageType; + this.name = "image"; + const dimension = imageType.dimension; + this.origin = new Array(dimension); + this.origin.fill(0); + this.spacing = new Array(dimension); + this.spacing.fill(1); + this.direction = new Float64Array(dimension * dimension); + this.direction.fill(0); + for (let ii = 0; ii < dimension; ii++) { + setMatrixElement_default(this.direction, dimension, ii, ii, 1); + } + this.size = new Array(dimension); + this.size.fill(0); + this.metadata = /* @__PURE__ */ new Map(); + this.data = null; + } +}; +var image_default = Image; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/bufferToTypedArray.js +function bufferToTypedArray(wasmType, buffer) { + let typedArray = null; + switch (wasmType) { + case int_types_default.UInt8: { + typedArray = new Uint8Array(buffer); + break; + } + case int_types_default.Int8: { + typedArray = new Int8Array(buffer); + break; + } + case int_types_default.UInt16: { + typedArray = new Uint16Array(buffer); + break; + } + case int_types_default.Int16: { + typedArray = new Int16Array(buffer); + break; + } + case int_types_default.UInt32: { + typedArray = new Uint32Array(buffer); + break; + } + case int_types_default.Int32: { + typedArray = new Int32Array(buffer); + break; + } + case int_types_default.UInt64: { + if (typeof globalThis.BigUint64Array === "function") { + typedArray = new BigUint64Array(buffer); + } else { + typedArray = new Uint8Array(buffer); + } + break; + } + case int_types_default.Int64: { + if (typeof globalThis.BigInt64Array === "function") { + typedArray = new BigInt64Array(buffer); + } else { + typedArray = new Uint8Array(buffer); + } + break; + } + case float_types_default.Float32: { + typedArray = new Float32Array(buffer); + break; + } + case float_types_default.Float64: { + typedArray = new Float64Array(buffer); + break; + } + case "null": { + typedArray = null; + break; + } + case null: { + typedArray = null; + break; + } + default: + throw new Error("Type is not supported as a TypedArray"); + } + return typedArray; +} +var bufferToTypedArray_default = bufferToTypedArray; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/copyImage.js +function copyImage(image) { + const copy = new image_default(image.imageType); + copy.name = image.name; + copy.origin = Array.from(image.origin); + copy.spacing = Array.from(image.spacing); + copy.direction = image.direction.slice(); + copy.size = Array.from(image.size); + if (image.data !== null) { + const CTor = image.data.constructor; + copy.data = new CTor(image.data.length); + if (copy.data != null) { + copy.data.set(image.data, 0); + } + } + return copy; +} +var copyImage_default = copyImage; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/stackImages.js +function stackImages(images) { + if (images.length < 1) { + throw Error("At least one images is required."); + } + const firstImage = images[0]; + if (firstImage.data === null) { + throw Error("Image data is null."); + } + const result = new image_default(firstImage.imageType); + result.origin = Array.from(firstImage.origin); + result.spacing = Array.from(firstImage.spacing); + const dimension = result.imageType.dimension; + result.direction = firstImage.direction.slice(); + const stackOn = dimension - 1; + result.size = Array.from(firstImage.size); + const stackedSize = images.reduce((accumulator, currentValue) => { + return accumulator + currentValue.size[stackOn]; + }, 0); + result.size[stackOn] = stackedSize; + const dataSize = result.size.reduce((accumulator, currentValue) => { + return accumulator * currentValue; + }, 1) * result.imageType.components; + const CTor = firstImage.data.constructor; + result.data = new CTor(dataSize); + let offsetBase = result.imageType.components; + for (let subIndex = 0; subIndex < result.size.length - 1; subIndex++) { + offsetBase *= result.size[subIndex]; + } + let stackIndex = 0; + if (result.data != null) { + for (let index = 0; index < images.length; index++) { + result.data.set(images[index].data, offsetBase * stackIndex); + stackIndex += images[index].size[stackOn]; + } + } else { + throw Error("Could not create result image data."); + } + return result; +} +var stackImages_default = stackImages; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/castImage.js +function castImage(inputImage, options) { + const outputImageType = Object.assign({}, inputImage.imageType); + if (typeof options !== "undefined" && typeof options.pixelType !== "undefined") { + outputImageType.pixelType = options.pixelType; + if (options.pixelType === pixel_types_default.Scalar && outputImageType.components !== 1) { + throw new Error("Cannot cast multi-component image to a scalar image"); + } + } + if (typeof options !== "undefined" && typeof options.componentType !== "undefined" && options.componentType !== inputImage.imageType.componentType) { + outputImageType.componentType = options.componentType; + } + const outputImage = new image_default(outputImageType); + outputImage.name = inputImage.name; + outputImage.origin = Array.from(inputImage.origin); + outputImage.spacing = Array.from(inputImage.spacing); + outputImage.direction = inputImage.direction.slice(); + outputImage.size = Array.from(inputImage.size); + outputImage.metadata = new Map(JSON.parse(JSON.stringify(Array.from(inputImage.metadata)))); + if (inputImage.data !== null) { + if (typeof options !== "undefined" && typeof options.componentType !== "undefined" && options.componentType !== inputImage.imageType.componentType) { + switch (inputImage.imageType.componentType) { + case int_types_default.UInt8: + case int_types_default.Int8: + case int_types_default.UInt16: + case int_types_default.Int16: + case int_types_default.UInt32: + case int_types_default.Int32: + case float_types_default.Float32: + case float_types_default.Float64: + switch (outputImage.imageType.componentType) { + case int_types_default.UInt8: + outputImage.data = new Uint8Array(inputImage.data); + break; + case int_types_default.Int8: + outputImage.data = new Int8Array(inputImage.data); + break; + case int_types_default.UInt16: + outputImage.data = new Uint16Array(inputImage.data); + break; + case int_types_default.Int16: + outputImage.data = new Int16Array(inputImage.data); + break; + case int_types_default.UInt32: + outputImage.data = new Uint32Array(inputImage.data); + break; + case int_types_default.Int32: + outputImage.data = new Int32Array(inputImage.data); + break; + case float_types_default.Float32: + outputImage.data = new Float32Array(inputImage.data); + break; + case float_types_default.Float64: + outputImage.data = new Float64Array(inputImage.data); + break; + case int_types_default.UInt64: + outputImage.data = new BigUint64Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = BigInt.asIntN(64, BigInt(inputImage.data[idx])); + } + break; + case int_types_default.Int64: + outputImage.data = new BigInt64Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = BigInt.asUintN(64, BigInt(inputImage.data[idx])); + } + break; + } + break; + case int_types_default.UInt64: + case int_types_default.Int64: + switch (outputImage.imageType.componentType) { + case int_types_default.UInt8: + outputImage.data = new Uint8Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case int_types_default.Int8: + outputImage.data = new Int8Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case int_types_default.UInt16: + outputImage.data = new Uint16Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case int_types_default.Int16: + outputImage.data = new Int16Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case int_types_default.UInt32: + outputImage.data = new Uint32Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case int_types_default.Int32: + outputImage.data = new Int32Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case float_types_default.Float32: + outputImage.data = new Float32Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case float_types_default.Float64: + outputImage.data = new Float64Array(inputImage.data.length); + for (let idx = 0; idx < outputImage.data.length; idx++) { + outputImage.data[idx] = Number(inputImage.data[idx]); + } + break; + case int_types_default.UInt64: + outputImage.data = new BigUint64Array(inputImage.data); + break; + case int_types_default.Int64: + outputImage.data = new BigInt64Array(inputImage.data); + break; + } + break; + } + } else { + const CTor = inputImage.data.constructor; + outputImage.data = new CTor(inputImage.data.length); + if (outputImage.data != null) { + outputImage.data.set(inputImage.data, 0); + } + } + } + return outputImage; +} +var castImage_default = castImage; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/WorkerPool.js +var __rest = function(s, e) { + var t = {}; + for (var p in s) + if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (s != null && typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { + if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) + t[p[i]] = s[p[i]]; + } + return t; +}; +var WorkerPool = class { + /* poolSize is the maximum number of web workers to create in the pool. + * + * The function, fcn, should accept null or an existing worker as its first argument. + * It most also return and object with the used worker on the `webWorker` + * property. * Example: runPipeline. + * + **/ + constructor(poolSize, fcn) { + this.fcn = fcn; + this.workerQueue = new Array(poolSize); + this.workerQueue.fill(null); + this.runInfo = []; + } + /* + * Run the tasks specified by the arguments in the taskArgsArray that will + * be passed to the pool fcn. + * + * An optional progressCallback will be called with the number of complete + * tasks and the total number of tasks as arguments every time a task has + * completed. + * + * Returns an object containing a promise ('promise') to communicate results + * as well as an id ('runId') which can be used to cancel any remaining pending + * tasks before they complete. + */ + runTasks(taskArgsArray, progressCallback = null) { + const info = { + taskQueue: [], + results: [], + addingTasks: false, + postponed: false, + runningWorkers: 0, + index: 0, + completedTasks: 0, + progressCallback, + canceled: false + }; + this.runInfo.push(info); + info.index = this.runInfo.length - 1; + return { + promise: new Promise((resolve, reject) => { + info.resolve = resolve; + info.reject = reject; + info.results = new Array(taskArgsArray.length); + info.completedTasks = 0; + info.addingTasks = true; + taskArgsArray.forEach((taskArg, index) => { + this.addTask(info.index, index, taskArg); + }); + info.addingTasks = false; + }), + runId: info.index + }; + } + terminateWorkers() { + for (let index = 0; index < this.workerQueue.length; index++) { + const worker = this.workerQueue[index]; + if (worker != null) { + worker.terminate(); + } + this.workerQueue[index] = null; + } + } + cancel(runId) { + const info = this.runInfo[runId]; + if (info !== null && info !== void 0) { + info.canceled = true; + } + } + addTask(infoIndex, resultIndex, taskArgs) { + const info = this.runInfo[infoIndex]; + if ((info === null || info === void 0 ? void 0 : info.canceled) === true) { + info.reject("Remaining tasks canceled"); + this.clearTask(info.index); + return; + } + if (this.workerQueue.length > 0) { + const worker = this.workerQueue.pop(); + info.runningWorkers++; + this.fcn(worker, ...taskArgs).then((_a) => { + var { webWorker } = _a, result = __rest(_a, ["webWorker"]); + this.workerQueue.push(webWorker); + if (this.runInfo[infoIndex] !== null) { + info.runningWorkers--; + info.results[resultIndex] = result; + info.completedTasks++; + if (info.progressCallback != null) { + info.progressCallback(info.completedTasks, info.results.length); + } + if (info.taskQueue.length > 0) { + const reTask = info.taskQueue.shift(); + this.addTask(infoIndex, reTask[0], reTask[1]); + } else if (!info.addingTasks && info.runningWorkers === 0) { + const results = info.results; + info.resolve(results); + this.clearTask(info.index); + } + } + }).catch((error) => { + info.reject(error); + this.clearTask(info.index); + }); + } else { + if (info.runningWorkers !== 0 || info.postponed) { + info.taskQueue.push([resultIndex, taskArgs]); + } else { + info.postponed = true; + setTimeout(() => { + info.postponed = false; + this.addTask(info.index, resultIndex, taskArgs); + }, 50); + } + } + } + clearTask(clearIndex) { + this.runInfo[clearIndex].results = []; + this.runInfo[clearIndex].taskQueue = []; + this.runInfo[clearIndex].progressCallback = null; + this.runInfo[clearIndex].canceled = null; + this.runInfo[clearIndex].reject = () => { + }; + this.runInfo[clearIndex].resolve = () => { + }; + } +}; +var WorkerPool_default = WorkerPool; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/getTransferables.js +var haveSharedArrayBuffer = typeof globalThis.SharedArrayBuffer !== "undefined"; +function getTransferables(data) { + if (data === void 0 || data === null) { + return []; + } + const transferables = []; + for (let i = 0; i < data.length; i++) { + const transferable = getTransferable(data[i]); + if (transferable !== null) { + transferables.push(transferable); + } + } + return transferables; +} +function getTransferable(data) { + if (data === void 0 || data === null) { + return null; + } + let result = null; + if (data.buffer !== void 0) { + result = data.buffer; + } else if (data.byteLength !== void 0) { + result = data; + } + if (haveSharedArrayBuffer && result instanceof SharedArrayBuffer) { + return null; + } + return result; +} +var getTransferables_default = getTransferables; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/bind.js +function bind(fn, thisArg) { + return function wrap() { + return fn.apply(thisArg, arguments); + }; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/utils.js +var { toString } = Object.prototype; +var { getPrototypeOf } = Object; +var kindOf = ((cache) => (thing) => { + const str = toString.call(thing); + return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase()); +})(/* @__PURE__ */ Object.create(null)); +var kindOfTest = (type) => { + type = type.toLowerCase(); + return (thing) => kindOf(thing) === type; +}; +var typeOfTest = (type) => (thing) => typeof thing === type; +var { isArray } = Array; +var isUndefined = typeOfTest("undefined"); +function isBuffer(val) { + return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val); +} +var isArrayBuffer = kindOfTest("ArrayBuffer"); +function isArrayBufferView(val) { + let result; + if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) { + result = ArrayBuffer.isView(val); + } else { + result = val && val.buffer && isArrayBuffer(val.buffer); + } + return result; +} +var isString = typeOfTest("string"); +var isFunction = typeOfTest("function"); +var isNumber = typeOfTest("number"); +var isObject = (thing) => thing !== null && typeof thing === "object"; +var isBoolean = (thing) => thing === true || thing === false; +var isPlainObject = (val) => { + if (kindOf(val) !== "object") { + return false; + } + const prototype3 = getPrototypeOf(val); + return (prototype3 === null || prototype3 === Object.prototype || Object.getPrototypeOf(prototype3) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val); +}; +var isDate = kindOfTest("Date"); +var isFile = kindOfTest("File"); +var isBlob = kindOfTest("Blob"); +var isFileList = kindOfTest("FileList"); +var isStream = (val) => isObject(val) && isFunction(val.pipe); +var isFormData = (thing) => { + let kind; + return thing && (typeof FormData === "function" && thing instanceof FormData || isFunction(thing.append) && ((kind = kindOf(thing)) === "formdata" || // detect form-data instance + kind === "object" && isFunction(thing.toString) && thing.toString() === "[object FormData]")); +}; +var isURLSearchParams = kindOfTest("URLSearchParams"); +var trim = (str) => str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); +function forEach(obj, fn, { allOwnKeys = false } = {}) { + if (obj === null || typeof obj === "undefined") { + return; + } + let i; + let l; + if (typeof obj !== "object") { + obj = [obj]; + } + if (isArray(obj)) { + for (i = 0, l = obj.length; i < l; i++) { + fn.call(null, obj[i], i, obj); + } + } else { + const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj); + const len = keys.length; + let key; + for (i = 0; i < len; i++) { + key = keys[i]; + fn.call(null, obj[key], key, obj); + } + } +} +function findKey(obj, key) { + key = key.toLowerCase(); + const keys = Object.keys(obj); + let i = keys.length; + let _key; + while (i-- > 0) { + _key = keys[i]; + if (key === _key.toLowerCase()) { + return _key; + } + } + return null; +} +var _global = (() => { + if (typeof globalThis !== "undefined") + return globalThis; + return typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : global; +})(); +var isContextDefined = (context) => !isUndefined(context) && context !== _global; +function merge() { + const { caseless } = isContextDefined(this) && this || {}; + const result = {}; + const assignValue = (val, key) => { + const targetKey = caseless && findKey(result, key) || key; + if (isPlainObject(result[targetKey]) && isPlainObject(val)) { + result[targetKey] = merge(result[targetKey], val); + } else if (isPlainObject(val)) { + result[targetKey] = merge({}, val); + } else if (isArray(val)) { + result[targetKey] = val.slice(); + } else { + result[targetKey] = val; + } + }; + for (let i = 0, l = arguments.length; i < l; i++) { + arguments[i] && forEach(arguments[i], assignValue); + } + return result; +} +var extend = (a, b, thisArg, { allOwnKeys } = {}) => { + forEach(b, (val, key) => { + if (thisArg && isFunction(val)) { + a[key] = bind(val, thisArg); + } else { + a[key] = val; + } + }, { allOwnKeys }); + return a; +}; +var stripBOM = (content) => { + if (content.charCodeAt(0) === 65279) { + content = content.slice(1); + } + return content; +}; +var inherits = (constructor, superConstructor, props, descriptors2) => { + constructor.prototype = Object.create(superConstructor.prototype, descriptors2); + constructor.prototype.constructor = constructor; + Object.defineProperty(constructor, "super", { + value: superConstructor.prototype + }); + props && Object.assign(constructor.prototype, props); +}; +var toFlatObject = (sourceObj, destObj, filter2, propFilter) => { + let props; + let i; + let prop; + const merged = {}; + destObj = destObj || {}; + if (sourceObj == null) + return destObj; + do { + props = Object.getOwnPropertyNames(sourceObj); + i = props.length; + while (i-- > 0) { + prop = props[i]; + if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) { + destObj[prop] = sourceObj[prop]; + merged[prop] = true; + } + } + sourceObj = filter2 !== false && getPrototypeOf(sourceObj); + } while (sourceObj && (!filter2 || filter2(sourceObj, destObj)) && sourceObj !== Object.prototype); + return destObj; +}; +var endsWith = (str, searchString, position) => { + str = String(str); + if (position === void 0 || position > str.length) { + position = str.length; + } + position -= searchString.length; + const lastIndex = str.indexOf(searchString, position); + return lastIndex !== -1 && lastIndex === position; +}; +var toArray = (thing) => { + if (!thing) + return null; + if (isArray(thing)) + return thing; + let i = thing.length; + if (!isNumber(i)) + return null; + const arr = new Array(i); + while (i-- > 0) { + arr[i] = thing[i]; + } + return arr; +}; +var isTypedArray = ((TypedArray) => { + return (thing) => { + return TypedArray && thing instanceof TypedArray; + }; +})(typeof Uint8Array !== "undefined" && getPrototypeOf(Uint8Array)); +var forEachEntry = (obj, fn) => { + const generator = obj && obj[Symbol.iterator]; + const iterator = generator.call(obj); + let result; + while ((result = iterator.next()) && !result.done) { + const pair = result.value; + fn.call(obj, pair[0], pair[1]); + } +}; +var matchAll = (regExp, str) => { + let matches; + const arr = []; + while ((matches = regExp.exec(str)) !== null) { + arr.push(matches); + } + return arr; +}; +var isHTMLForm = kindOfTest("HTMLFormElement"); +var toCamelCase = (str) => { + return str.toLowerCase().replace( + /[-_\s]([a-z\d])(\w*)/g, + function replacer(m, p1, p2) { + return p1.toUpperCase() + p2; + } + ); +}; +var hasOwnProperty = (({ hasOwnProperty: hasOwnProperty2 }) => (obj, prop) => hasOwnProperty2.call(obj, prop))(Object.prototype); +var isRegExp = kindOfTest("RegExp"); +var reduceDescriptors = (obj, reducer) => { + const descriptors2 = Object.getOwnPropertyDescriptors(obj); + const reducedDescriptors = {}; + forEach(descriptors2, (descriptor, name) => { + let ret; + if ((ret = reducer(descriptor, name, obj)) !== false) { + reducedDescriptors[name] = ret || descriptor; + } + }); + Object.defineProperties(obj, reducedDescriptors); +}; +var freezeMethods = (obj) => { + reduceDescriptors(obj, (descriptor, name) => { + if (isFunction(obj) && ["arguments", "caller", "callee"].indexOf(name) !== -1) { + return false; + } + const value = obj[name]; + if (!isFunction(value)) + return; + descriptor.enumerable = false; + if ("writable" in descriptor) { + descriptor.writable = false; + return; + } + if (!descriptor.set) { + descriptor.set = () => { + throw Error("Can not rewrite read-only method '" + name + "'"); + }; + } + }); +}; +var toObjectSet = (arrayOrString, delimiter) => { + const obj = {}; + const define = (arr) => { + arr.forEach((value) => { + obj[value] = true; + }); + }; + isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter)); + return obj; +}; +var noop = () => { +}; +var toFiniteNumber = (value, defaultValue) => { + value = +value; + return Number.isFinite(value) ? value : defaultValue; +}; +var ALPHA = "abcdefghijklmnopqrstuvwxyz"; +var DIGIT = "0123456789"; +var ALPHABET = { + DIGIT, + ALPHA, + ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT +}; +var generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => { + let str = ""; + const { length } = alphabet; + while (size--) { + str += alphabet[Math.random() * length | 0]; + } + return str; +}; +function isSpecCompliantForm(thing) { + return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === "FormData" && thing[Symbol.iterator]); +} +var toJSONObject = (obj) => { + const stack = new Array(10); + const visit = (source, i) => { + if (isObject(source)) { + if (stack.indexOf(source) >= 0) { + return; + } + if (!("toJSON" in source)) { + stack[i] = source; + const target = isArray(source) ? [] : {}; + forEach(source, (value, key) => { + const reducedValue = visit(value, i + 1); + !isUndefined(reducedValue) && (target[key] = reducedValue); + }); + stack[i] = void 0; + return target; + } + } + return source; + }; + return visit(obj, 0); +}; +var isAsyncFn = kindOfTest("AsyncFunction"); +var isThenable = (thing) => thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch); +var utils_default = { + isArray, + isArrayBuffer, + isBuffer, + isFormData, + isArrayBufferView, + isString, + isNumber, + isBoolean, + isObject, + isPlainObject, + isUndefined, + isDate, + isFile, + isBlob, + isRegExp, + isFunction, + isStream, + isURLSearchParams, + isTypedArray, + isFileList, + forEach, + merge, + extend, + trim, + stripBOM, + inherits, + toFlatObject, + kindOf, + kindOfTest, + endsWith, + toArray, + forEachEntry, + matchAll, + isHTMLForm, + hasOwnProperty, + hasOwnProp: hasOwnProperty, + // an alias to avoid ESLint no-prototype-builtins detection + reduceDescriptors, + freezeMethods, + toObjectSet, + toCamelCase, + noop, + toFiniteNumber, + findKey, + global: _global, + isContextDefined, + ALPHABET, + generateString, + isSpecCompliantForm, + toJSONObject, + isAsyncFn, + isThenable +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/AxiosError.js +function AxiosError(message, code, config, request, response) { + Error.call(this); + if (Error.captureStackTrace) { + Error.captureStackTrace(this, this.constructor); + } else { + this.stack = new Error().stack; + } + this.message = message; + this.name = "AxiosError"; + code && (this.code = code); + config && (this.config = config); + request && (this.request = request); + response && (this.response = response); +} +utils_default.inherits(AxiosError, Error, { + toJSON: function toJSON() { + return { + // Standard + message: this.message, + name: this.name, + // Microsoft + description: this.description, + number: this.number, + // Mozilla + fileName: this.fileName, + lineNumber: this.lineNumber, + columnNumber: this.columnNumber, + stack: this.stack, + // Axios + config: utils_default.toJSONObject(this.config), + code: this.code, + status: this.response && this.response.status ? this.response.status : null + }; + } +}); +var prototype = AxiosError.prototype; +var descriptors = {}; +[ + "ERR_BAD_OPTION_VALUE", + "ERR_BAD_OPTION", + "ECONNABORTED", + "ETIMEDOUT", + "ERR_NETWORK", + "ERR_FR_TOO_MANY_REDIRECTS", + "ERR_DEPRECATED", + "ERR_BAD_RESPONSE", + "ERR_BAD_REQUEST", + "ERR_CANCELED", + "ERR_NOT_SUPPORT", + "ERR_INVALID_URL" + // eslint-disable-next-line func-names +].forEach((code) => { + descriptors[code] = { value: code }; +}); +Object.defineProperties(AxiosError, descriptors); +Object.defineProperty(prototype, "isAxiosError", { value: true }); +AxiosError.from = (error, code, config, request, response, customProps) => { + const axiosError = Object.create(prototype); + utils_default.toFlatObject(error, axiosError, function filter2(obj) { + return obj !== Error.prototype; + }, (prop) => { + return prop !== "isAxiosError"; + }); + AxiosError.call(axiosError, error.message, code, config, request, response); + axiosError.cause = error; + axiosError.name = error.name; + customProps && Object.assign(axiosError, customProps); + return axiosError; +}; +var AxiosError_default = AxiosError; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/null.js +var null_default = null; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/toFormData.js +function isVisitable(thing) { + return utils_default.isPlainObject(thing) || utils_default.isArray(thing); +} +function removeBrackets(key) { + return utils_default.endsWith(key, "[]") ? key.slice(0, -2) : key; +} +function renderKey(path, key, dots) { + if (!path) + return key; + return path.concat(key).map(function each(token, i) { + token = removeBrackets(token); + return !dots && i ? "[" + token + "]" : token; + }).join(dots ? "." : ""); +} +function isFlatArray(arr) { + return utils_default.isArray(arr) && !arr.some(isVisitable); +} +var predicates = utils_default.toFlatObject(utils_default, {}, null, function filter(prop) { + return /^is[A-Z]/.test(prop); +}); +function toFormData(obj, formData, options) { + if (!utils_default.isObject(obj)) { + throw new TypeError("target must be an object"); + } + formData = formData || new (null_default || FormData)(); + options = utils_default.toFlatObject(options, { + metaTokens: true, + dots: false, + indexes: false + }, false, function defined(option, source) { + return !utils_default.isUndefined(source[option]); + }); + const metaTokens = options.metaTokens; + const visitor = options.visitor || defaultVisitor; + const dots = options.dots; + const indexes = options.indexes; + const _Blob = options.Blob || typeof Blob !== "undefined" && Blob; + const useBlob = _Blob && utils_default.isSpecCompliantForm(formData); + if (!utils_default.isFunction(visitor)) { + throw new TypeError("visitor must be a function"); + } + function convertValue(value) { + if (value === null) + return ""; + if (utils_default.isDate(value)) { + return value.toISOString(); + } + if (!useBlob && utils_default.isBlob(value)) { + throw new AxiosError_default("Blob is not supported. Use a Buffer instead."); + } + if (utils_default.isArrayBuffer(value) || utils_default.isTypedArray(value)) { + return useBlob && typeof Blob === "function" ? new Blob([value]) : Buffer.from(value); + } + return value; + } + function defaultVisitor(value, key, path) { + let arr = value; + if (value && !path && typeof value === "object") { + if (utils_default.endsWith(key, "{}")) { + key = metaTokens ? key : key.slice(0, -2); + value = JSON.stringify(value); + } else if (utils_default.isArray(value) && isFlatArray(value) || (utils_default.isFileList(value) || utils_default.endsWith(key, "[]")) && (arr = utils_default.toArray(value))) { + key = removeBrackets(key); + arr.forEach(function each(el, index) { + !(utils_default.isUndefined(el) || el === null) && formData.append( + // eslint-disable-next-line no-nested-ternary + indexes === true ? renderKey([key], index, dots) : indexes === null ? key : key + "[]", + convertValue(el) + ); + }); + return false; + } + } + if (isVisitable(value)) { + return true; + } + formData.append(renderKey(path, key, dots), convertValue(value)); + return false; + } + const stack = []; + const exposedHelpers = Object.assign(predicates, { + defaultVisitor, + convertValue, + isVisitable + }); + function build(value, path) { + if (utils_default.isUndefined(value)) + return; + if (stack.indexOf(value) !== -1) { + throw Error("Circular reference detected in " + path.join(".")); + } + stack.push(value); + utils_default.forEach(value, function each(el, key) { + const result = !(utils_default.isUndefined(el) || el === null) && visitor.call( + formData, + el, + utils_default.isString(key) ? key.trim() : key, + path, + exposedHelpers + ); + if (result === true) { + build(el, path ? path.concat(key) : [key]); + } + }); + stack.pop(); + } + if (!utils_default.isObject(obj)) { + throw new TypeError("data must be an object"); + } + build(obj); + return formData; +} +var toFormData_default = toFormData; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/AxiosURLSearchParams.js +function encode(str) { + const charMap = { + "!": "%21", + "'": "%27", + "(": "%28", + ")": "%29", + "~": "%7E", + "%20": "+", + "%00": "\0" + }; + return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) { + return charMap[match]; + }); +} +function AxiosURLSearchParams(params, options) { + this._pairs = []; + params && toFormData_default(params, this, options); +} +var prototype2 = AxiosURLSearchParams.prototype; +prototype2.append = function append(name, value) { + this._pairs.push([name, value]); +}; +prototype2.toString = function toString2(encoder2) { + const _encode = encoder2 ? function(value) { + return encoder2.call(this, value, encode); + } : encode; + return this._pairs.map(function each(pair) { + return _encode(pair[0]) + "=" + _encode(pair[1]); + }, "").join("&"); +}; +var AxiosURLSearchParams_default = AxiosURLSearchParams; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/buildURL.js +function encode2(val) { + return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]"); +} +function buildURL(url, params, options) { + if (!params) { + return url; + } + const _encode = options && options.encode || encode2; + const serializeFn = options && options.serialize; + let serializedParams; + if (serializeFn) { + serializedParams = serializeFn(params, options); + } else { + serializedParams = utils_default.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams_default(params, options).toString(_encode); + } + if (serializedParams) { + const hashmarkIndex = url.indexOf("#"); + if (hashmarkIndex !== -1) { + url = url.slice(0, hashmarkIndex); + } + url += (url.indexOf("?") === -1 ? "?" : "&") + serializedParams; + } + return url; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/InterceptorManager.js +var InterceptorManager = class { + constructor() { + this.handlers = []; + } + /** + * Add a new interceptor to the stack + * + * @param {Function} fulfilled The function to handle `then` for a `Promise` + * @param {Function} rejected The function to handle `reject` for a `Promise` + * + * @return {Number} An ID used to remove interceptor later + */ + use(fulfilled, rejected, options) { + this.handlers.push({ + fulfilled, + rejected, + synchronous: options ? options.synchronous : false, + runWhen: options ? options.runWhen : null + }); + return this.handlers.length - 1; + } + /** + * Remove an interceptor from the stack + * + * @param {Number} id The ID that was returned by `use` + * + * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise + */ + eject(id) { + if (this.handlers[id]) { + this.handlers[id] = null; + } + } + /** + * Clear all interceptors from the stack + * + * @returns {void} + */ + clear() { + if (this.handlers) { + this.handlers = []; + } + } + /** + * Iterate over all the registered interceptors + * + * This method is particularly useful for skipping over any + * interceptors that may have become `null` calling `eject`. + * + * @param {Function} fn The function to call for each interceptor + * + * @returns {void} + */ + forEach(fn) { + utils_default.forEach(this.handlers, function forEachHandler(h) { + if (h !== null) { + fn(h); + } + }); + } +}; +var InterceptorManager_default = InterceptorManager; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/defaults/transitional.js +var transitional_default = { + silentJSONParsing: true, + forcedJSONParsing: true, + clarifyTimeoutError: false +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js +var URLSearchParams_default = typeof URLSearchParams !== "undefined" ? URLSearchParams : AxiosURLSearchParams_default; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/classes/FormData.js +var FormData_default = typeof FormData !== "undefined" ? FormData : null; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/classes/Blob.js +var Blob_default = typeof Blob !== "undefined" ? Blob : null; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/index.js +var isStandardBrowserEnv = (() => { + let product; + if (typeof navigator !== "undefined" && ((product = navigator.product) === "ReactNative" || product === "NativeScript" || product === "NS")) { + return false; + } + return typeof window !== "undefined" && typeof document !== "undefined"; +})(); +var isStandardBrowserWebWorkerEnv = (() => { + return typeof WorkerGlobalScope !== "undefined" && // eslint-disable-next-line no-undef + self instanceof WorkerGlobalScope && typeof self.importScripts === "function"; +})(); +var browser_default = { + isBrowser: true, + classes: { + URLSearchParams: URLSearchParams_default, + FormData: FormData_default, + Blob: Blob_default + }, + isStandardBrowserEnv, + isStandardBrowserWebWorkerEnv, + protocols: ["http", "https", "file", "blob", "url", "data"] +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/toURLEncodedForm.js +function toURLEncodedForm(data, options) { + return toFormData_default(data, new browser_default.classes.URLSearchParams(), Object.assign({ + visitor: function(value, key, path, helpers) { + if (browser_default.isNode && utils_default.isBuffer(value)) { + this.append(key, value.toString("base64")); + return false; + } + return helpers.defaultVisitor.apply(this, arguments); + } + }, options)); +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/formDataToJSON.js +function parsePropPath(name) { + return utils_default.matchAll(/\w+|\[(\w*)]/g, name).map((match) => { + return match[0] === "[]" ? "" : match[1] || match[0]; + }); +} +function arrayToObject(arr) { + const obj = {}; + const keys = Object.keys(arr); + let i; + const len = keys.length; + let key; + for (i = 0; i < len; i++) { + key = keys[i]; + obj[key] = arr[key]; + } + return obj; +} +function formDataToJSON(formData) { + function buildPath(path, value, target, index) { + let name = path[index++]; + const isNumericKey = Number.isFinite(+name); + const isLast = index >= path.length; + name = !name && utils_default.isArray(target) ? target.length : name; + if (isLast) { + if (utils_default.hasOwnProp(target, name)) { + target[name] = [target[name], value]; + } else { + target[name] = value; + } + return !isNumericKey; + } + if (!target[name] || !utils_default.isObject(target[name])) { + target[name] = []; + } + const result = buildPath(path, value, target[name], index); + if (result && utils_default.isArray(target[name])) { + target[name] = arrayToObject(target[name]); + } + return !isNumericKey; + } + if (utils_default.isFormData(formData) && utils_default.isFunction(formData.entries)) { + const obj = {}; + utils_default.forEachEntry(formData, (name, value) => { + buildPath(parsePropPath(name), value, obj, 0); + }); + return obj; + } + return null; +} +var formDataToJSON_default = formDataToJSON; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/defaults/index.js +function stringifySafely(rawValue, parser, encoder2) { + if (utils_default.isString(rawValue)) { + try { + (parser || JSON.parse)(rawValue); + return utils_default.trim(rawValue); + } catch (e) { + if (e.name !== "SyntaxError") { + throw e; + } + } + } + return (encoder2 || JSON.stringify)(rawValue); +} +var defaults = { + transitional: transitional_default, + adapter: ["xhr", "http"], + transformRequest: [function transformRequest(data, headers) { + const contentType = headers.getContentType() || ""; + const hasJSONContentType = contentType.indexOf("application/json") > -1; + const isObjectPayload = utils_default.isObject(data); + if (isObjectPayload && utils_default.isHTMLForm(data)) { + data = new FormData(data); + } + const isFormData2 = utils_default.isFormData(data); + if (isFormData2) { + if (!hasJSONContentType) { + return data; + } + return hasJSONContentType ? JSON.stringify(formDataToJSON_default(data)) : data; + } + if (utils_default.isArrayBuffer(data) || utils_default.isBuffer(data) || utils_default.isStream(data) || utils_default.isFile(data) || utils_default.isBlob(data)) { + return data; + } + if (utils_default.isArrayBufferView(data)) { + return data.buffer; + } + if (utils_default.isURLSearchParams(data)) { + headers.setContentType("application/x-www-form-urlencoded;charset=utf-8", false); + return data.toString(); + } + let isFileList2; + if (isObjectPayload) { + if (contentType.indexOf("application/x-www-form-urlencoded") > -1) { + return toURLEncodedForm(data, this.formSerializer).toString(); + } + if ((isFileList2 = utils_default.isFileList(data)) || contentType.indexOf("multipart/form-data") > -1) { + const _FormData = this.env && this.env.FormData; + return toFormData_default( + isFileList2 ? { "files[]": data } : data, + _FormData && new _FormData(), + this.formSerializer + ); + } + } + if (isObjectPayload || hasJSONContentType) { + headers.setContentType("application/json", false); + return stringifySafely(data); + } + return data; + }], + transformResponse: [function transformResponse(data) { + const transitional2 = this.transitional || defaults.transitional; + const forcedJSONParsing = transitional2 && transitional2.forcedJSONParsing; + const JSONRequested = this.responseType === "json"; + if (data && utils_default.isString(data) && (forcedJSONParsing && !this.responseType || JSONRequested)) { + const silentJSONParsing = transitional2 && transitional2.silentJSONParsing; + const strictJSONParsing = !silentJSONParsing && JSONRequested; + try { + return JSON.parse(data); + } catch (e) { + if (strictJSONParsing) { + if (e.name === "SyntaxError") { + throw AxiosError_default.from(e, AxiosError_default.ERR_BAD_RESPONSE, this, null, this.response); + } + throw e; + } + } + } + return data; + }], + /** + * A timeout in milliseconds to abort a request. If set to 0 (default) a + * timeout is not created. + */ + timeout: 0, + xsrfCookieName: "XSRF-TOKEN", + xsrfHeaderName: "X-XSRF-TOKEN", + maxContentLength: -1, + maxBodyLength: -1, + env: { + FormData: browser_default.classes.FormData, + Blob: browser_default.classes.Blob + }, + validateStatus: function validateStatus(status) { + return status >= 200 && status < 300; + }, + headers: { + common: { + "Accept": "application/json, text/plain, */*", + "Content-Type": void 0 + } + } +}; +utils_default.forEach(["delete", "get", "head", "post", "put", "patch"], (method) => { + defaults.headers[method] = {}; +}); +var defaults_default = defaults; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/parseHeaders.js +var ignoreDuplicateOf = utils_default.toObjectSet([ + "age", + "authorization", + "content-length", + "content-type", + "etag", + "expires", + "from", + "host", + "if-modified-since", + "if-unmodified-since", + "last-modified", + "location", + "max-forwards", + "proxy-authorization", + "referer", + "retry-after", + "user-agent" +]); +var parseHeaders_default = (rawHeaders) => { + const parsed = {}; + let key; + let val; + let i; + rawHeaders && rawHeaders.split("\n").forEach(function parser(line) { + i = line.indexOf(":"); + key = line.substring(0, i).trim().toLowerCase(); + val = line.substring(i + 1).trim(); + if (!key || parsed[key] && ignoreDuplicateOf[key]) { + return; + } + if (key === "set-cookie") { + if (parsed[key]) { + parsed[key].push(val); + } else { + parsed[key] = [val]; + } + } else { + parsed[key] = parsed[key] ? parsed[key] + ", " + val : val; + } + }); + return parsed; +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/AxiosHeaders.js +var $internals = Symbol("internals"); +function normalizeHeader(header) { + return header && String(header).trim().toLowerCase(); +} +function normalizeValue(value) { + if (value === false || value == null) { + return value; + } + return utils_default.isArray(value) ? value.map(normalizeValue) : String(value); +} +function parseTokens(str) { + const tokens = /* @__PURE__ */ Object.create(null); + const tokensRE = /([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g; + let match; + while (match = tokensRE.exec(str)) { + tokens[match[1]] = match[2]; + } + return tokens; +} +var isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim()); +function matchHeaderValue(context, value, header, filter2, isHeaderNameFilter) { + if (utils_default.isFunction(filter2)) { + return filter2.call(this, value, header); + } + if (isHeaderNameFilter) { + value = header; + } + if (!utils_default.isString(value)) + return; + if (utils_default.isString(filter2)) { + return value.indexOf(filter2) !== -1; + } + if (utils_default.isRegExp(filter2)) { + return filter2.test(value); + } +} +function formatHeader(header) { + return header.trim().toLowerCase().replace(/([a-z\d])(\w*)/g, (w, char, str) => { + return char.toUpperCase() + str; + }); +} +function buildAccessors(obj, header) { + const accessorName = utils_default.toCamelCase(" " + header); + ["get", "set", "has"].forEach((methodName) => { + Object.defineProperty(obj, methodName + accessorName, { + value: function(arg1, arg2, arg3) { + return this[methodName].call(this, header, arg1, arg2, arg3); + }, + configurable: true + }); + }); +} +var AxiosHeaders = class { + constructor(headers) { + headers && this.set(headers); + } + set(header, valueOrRewrite, rewrite) { + const self2 = this; + function setHeader(_value, _header, _rewrite) { + const lHeader = normalizeHeader(_header); + if (!lHeader) { + throw new Error("header name must be a non-empty string"); + } + const key = utils_default.findKey(self2, lHeader); + if (!key || self2[key] === void 0 || _rewrite === true || _rewrite === void 0 && self2[key] !== false) { + self2[key || _header] = normalizeValue(_value); + } + } + const setHeaders = (headers, _rewrite) => utils_default.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite)); + if (utils_default.isPlainObject(header) || header instanceof this.constructor) { + setHeaders(header, valueOrRewrite); + } else if (utils_default.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) { + setHeaders(parseHeaders_default(header), valueOrRewrite); + } else { + header != null && setHeader(valueOrRewrite, header, rewrite); + } + return this; + } + get(header, parser) { + header = normalizeHeader(header); + if (header) { + const key = utils_default.findKey(this, header); + if (key) { + const value = this[key]; + if (!parser) { + return value; + } + if (parser === true) { + return parseTokens(value); + } + if (utils_default.isFunction(parser)) { + return parser.call(this, value, key); + } + if (utils_default.isRegExp(parser)) { + return parser.exec(value); + } + throw new TypeError("parser must be boolean|regexp|function"); + } + } + } + has(header, matcher) { + header = normalizeHeader(header); + if (header) { + const key = utils_default.findKey(this, header); + return !!(key && this[key] !== void 0 && (!matcher || matchHeaderValue(this, this[key], key, matcher))); + } + return false; + } + delete(header, matcher) { + const self2 = this; + let deleted = false; + function deleteHeader(_header) { + _header = normalizeHeader(_header); + if (_header) { + const key = utils_default.findKey(self2, _header); + if (key && (!matcher || matchHeaderValue(self2, self2[key], key, matcher))) { + delete self2[key]; + deleted = true; + } + } + } + if (utils_default.isArray(header)) { + header.forEach(deleteHeader); + } else { + deleteHeader(header); + } + return deleted; + } + clear(matcher) { + const keys = Object.keys(this); + let i = keys.length; + let deleted = false; + while (i--) { + const key = keys[i]; + if (!matcher || matchHeaderValue(this, this[key], key, matcher, true)) { + delete this[key]; + deleted = true; + } + } + return deleted; + } + normalize(format) { + const self2 = this; + const headers = {}; + utils_default.forEach(this, (value, header) => { + const key = utils_default.findKey(headers, header); + if (key) { + self2[key] = normalizeValue(value); + delete self2[header]; + return; + } + const normalized = format ? formatHeader(header) : String(header).trim(); + if (normalized !== header) { + delete self2[header]; + } + self2[normalized] = normalizeValue(value); + headers[normalized] = true; + }); + return this; + } + concat(...targets) { + return this.constructor.concat(this, ...targets); + } + toJSON(asStrings) { + const obj = /* @__PURE__ */ Object.create(null); + utils_default.forEach(this, (value, header) => { + value != null && value !== false && (obj[header] = asStrings && utils_default.isArray(value) ? value.join(", ") : value); + }); + return obj; + } + [Symbol.iterator]() { + return Object.entries(this.toJSON())[Symbol.iterator](); + } + toString() { + return Object.entries(this.toJSON()).map(([header, value]) => header + ": " + value).join("\n"); + } + get [Symbol.toStringTag]() { + return "AxiosHeaders"; + } + static from(thing) { + return thing instanceof this ? thing : new this(thing); + } + static concat(first, ...targets) { + const computed = new this(first); + targets.forEach((target) => computed.set(target)); + return computed; + } + static accessor(header) { + const internals = this[$internals] = this[$internals] = { + accessors: {} + }; + const accessors = internals.accessors; + const prototype3 = this.prototype; + function defineAccessor(_header) { + const lHeader = normalizeHeader(_header); + if (!accessors[lHeader]) { + buildAccessors(prototype3, _header); + accessors[lHeader] = true; + } + } + utils_default.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header); + return this; + } +}; +AxiosHeaders.accessor(["Content-Type", "Content-Length", "Accept", "Accept-Encoding", "User-Agent", "Authorization"]); +utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => { + let mapped = key[0].toUpperCase() + key.slice(1); + return { + get: () => value, + set(headerValue) { + this[mapped] = headerValue; + } + }; +}); +utils_default.freezeMethods(AxiosHeaders); +var AxiosHeaders_default = AxiosHeaders; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/transformData.js +function transformData(fns, response) { + const config = this || defaults_default; + const context = response || config; + const headers = AxiosHeaders_default.from(context.headers); + let data = context.data; + utils_default.forEach(fns, function transform(fn) { + data = fn.call(config, data, headers.normalize(), response ? response.status : void 0); + }); + headers.normalize(); + return data; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/cancel/isCancel.js +function isCancel(value) { + return !!(value && value.__CANCEL__); +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/cancel/CanceledError.js +function CanceledError(message, config, request) { + AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request); + this.name = "CanceledError"; +} +utils_default.inherits(CanceledError, AxiosError_default, { + __CANCEL__: true +}); +var CanceledError_default = CanceledError; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/settle.js +function settle(resolve, reject, response) { + const validateStatus2 = response.config.validateStatus; + if (!response.status || !validateStatus2 || validateStatus2(response.status)) { + resolve(response); + } else { + reject(new AxiosError_default( + "Request failed with status code " + response.status, + [AxiosError_default.ERR_BAD_REQUEST, AxiosError_default.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], + response.config, + response.request, + response + )); + } +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/cookies.js +var cookies_default = browser_default.isStandardBrowserEnv ? ( + // Standard browser envs support document.cookie + function standardBrowserEnv() { + return { + write: function write(name, value, expires, path, domain, secure) { + const cookie = []; + cookie.push(name + "=" + encodeURIComponent(value)); + if (utils_default.isNumber(expires)) { + cookie.push("expires=" + new Date(expires).toGMTString()); + } + if (utils_default.isString(path)) { + cookie.push("path=" + path); + } + if (utils_default.isString(domain)) { + cookie.push("domain=" + domain); + } + if (secure === true) { + cookie.push("secure"); + } + document.cookie = cookie.join("; "); + }, + read: function read(name) { + const match = document.cookie.match(new RegExp("(^|;\\s*)(" + name + ")=([^;]*)")); + return match ? decodeURIComponent(match[3]) : null; + }, + remove: function remove(name) { + this.write(name, "", Date.now() - 864e5); + } + }; + }() +) : ( + // Non standard browser env (web workers, react-native) lack needed support. + function nonStandardBrowserEnv() { + return { + write: function write() { + }, + read: function read() { + return null; + }, + remove: function remove() { + } + }; + }() +); + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/isAbsoluteURL.js +function isAbsoluteURL(url) { + return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url); +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/combineURLs.js +function combineURLs(baseURL, relativeURL) { + return relativeURL ? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "") : baseURL; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/buildFullPath.js +function buildFullPath(baseURL, requestedURL) { + if (baseURL && !isAbsoluteURL(requestedURL)) { + return combineURLs(baseURL, requestedURL); + } + return requestedURL; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/isURLSameOrigin.js +var isURLSameOrigin_default = browser_default.isStandardBrowserEnv ? ( + // Standard browser envs have full support of the APIs needed to test + // whether the request URL is of the same origin as current location. + function standardBrowserEnv2() { + const msie = /(msie|trident)/i.test(navigator.userAgent); + const urlParsingNode = document.createElement("a"); + let originURL; + function resolveURL(url) { + let href = url; + if (msie) { + urlParsingNode.setAttribute("href", href); + href = urlParsingNode.href; + } + urlParsingNode.setAttribute("href", href); + return { + href: urlParsingNode.href, + protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, "") : "", + host: urlParsingNode.host, + search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, "") : "", + hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, "") : "", + hostname: urlParsingNode.hostname, + port: urlParsingNode.port, + pathname: urlParsingNode.pathname.charAt(0) === "/" ? urlParsingNode.pathname : "/" + urlParsingNode.pathname + }; + } + originURL = resolveURL(window.location.href); + return function isURLSameOrigin(requestURL) { + const parsed = utils_default.isString(requestURL) ? resolveURL(requestURL) : requestURL; + return parsed.protocol === originURL.protocol && parsed.host === originURL.host; + }; + }() +) : ( + // Non standard browser envs (web workers, react-native) lack needed support. + function nonStandardBrowserEnv2() { + return function isURLSameOrigin() { + return true; + }; + }() +); + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/parseProtocol.js +function parseProtocol(url) { + const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url); + return match && match[1] || ""; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/speedometer.js +function speedometer(samplesCount, min) { + samplesCount = samplesCount || 10; + const bytes = new Array(samplesCount); + const timestamps = new Array(samplesCount); + let head = 0; + let tail = 0; + let firstSampleTS; + min = min !== void 0 ? min : 1e3; + return function push(chunkLength) { + const now = Date.now(); + const startedAt = timestamps[tail]; + if (!firstSampleTS) { + firstSampleTS = now; + } + bytes[head] = chunkLength; + timestamps[head] = now; + let i = tail; + let bytesCount = 0; + while (i !== head) { + bytesCount += bytes[i++]; + i = i % samplesCount; + } + head = (head + 1) % samplesCount; + if (head === tail) { + tail = (tail + 1) % samplesCount; + } + if (now - firstSampleTS < min) { + return; + } + const passed = startedAt && now - startedAt; + return passed ? Math.round(bytesCount * 1e3 / passed) : void 0; + }; +} +var speedometer_default = speedometer; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/adapters/xhr.js +function progressEventReducer(listener, isDownloadStream) { + let bytesNotified = 0; + const _speedometer = speedometer_default(50, 250); + return (e) => { + const loaded = e.loaded; + const total = e.lengthComputable ? e.total : void 0; + const progressBytes = loaded - bytesNotified; + const rate = _speedometer(progressBytes); + const inRange = loaded <= total; + bytesNotified = loaded; + const data = { + loaded, + total, + progress: total ? loaded / total : void 0, + bytes: progressBytes, + rate: rate ? rate : void 0, + estimated: rate && total && inRange ? (total - loaded) / rate : void 0, + event: e + }; + data[isDownloadStream ? "download" : "upload"] = true; + listener(data); + }; +} +var isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined"; +var xhr_default = isXHRAdapterSupported && function(config) { + return new Promise(function dispatchXhrRequest(resolve, reject) { + let requestData = config.data; + const requestHeaders = AxiosHeaders_default.from(config.headers).normalize(); + const responseType = config.responseType; + let onCanceled; + function done() { + if (config.cancelToken) { + config.cancelToken.unsubscribe(onCanceled); + } + if (config.signal) { + config.signal.removeEventListener("abort", onCanceled); + } + } + let contentType; + if (utils_default.isFormData(requestData)) { + if (browser_default.isStandardBrowserEnv || browser_default.isStandardBrowserWebWorkerEnv) { + requestHeaders.setContentType(false); + } else if (!requestHeaders.getContentType(/^\s*multipart\/form-data/)) { + requestHeaders.setContentType("multipart/form-data"); + } else if (utils_default.isString(contentType = requestHeaders.getContentType())) { + requestHeaders.setContentType(contentType.replace(/^\s*(multipart\/form-data);+/, "$1")); + } + } + let request = new XMLHttpRequest(); + if (config.auth) { + const username = config.auth.username || ""; + const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : ""; + requestHeaders.set("Authorization", "Basic " + btoa(username + ":" + password)); + } + const fullPath = buildFullPath(config.baseURL, config.url); + request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); + request.timeout = config.timeout; + function onloadend() { + if (!request) { + return; + } + const responseHeaders = AxiosHeaders_default.from( + "getAllResponseHeaders" in request && request.getAllResponseHeaders() + ); + const responseData = !responseType || responseType === "text" || responseType === "json" ? request.responseText : request.response; + const response = { + data: responseData, + status: request.status, + statusText: request.statusText, + headers: responseHeaders, + config, + request + }; + settle(function _resolve(value) { + resolve(value); + done(); + }, function _reject(err) { + reject(err); + done(); + }, response); + request = null; + } + if ("onloadend" in request) { + request.onloadend = onloadend; + } else { + request.onreadystatechange = function handleLoad() { + if (!request || request.readyState !== 4) { + return; + } + if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf("file:") === 0)) { + return; + } + setTimeout(onloadend); + }; + } + request.onabort = function handleAbort() { + if (!request) { + return; + } + reject(new AxiosError_default("Request aborted", AxiosError_default.ECONNABORTED, config, request)); + request = null; + }; + request.onerror = function handleError() { + reject(new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config, request)); + request = null; + }; + request.ontimeout = function handleTimeout() { + let timeoutErrorMessage = config.timeout ? "timeout of " + config.timeout + "ms exceeded" : "timeout exceeded"; + const transitional2 = config.transitional || transitional_default; + if (config.timeoutErrorMessage) { + timeoutErrorMessage = config.timeoutErrorMessage; + } + reject(new AxiosError_default( + timeoutErrorMessage, + transitional2.clarifyTimeoutError ? AxiosError_default.ETIMEDOUT : AxiosError_default.ECONNABORTED, + config, + request + )); + request = null; + }; + if (browser_default.isStandardBrowserEnv) { + const xsrfValue = isURLSameOrigin_default(fullPath) && config.xsrfCookieName && cookies_default.read(config.xsrfCookieName); + if (xsrfValue) { + requestHeaders.set(config.xsrfHeaderName, xsrfValue); + } + } + requestData === void 0 && requestHeaders.setContentType(null); + if ("setRequestHeader" in request) { + utils_default.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { + request.setRequestHeader(key, val); + }); + } + if (!utils_default.isUndefined(config.withCredentials)) { + request.withCredentials = !!config.withCredentials; + } + if (responseType && responseType !== "json") { + request.responseType = config.responseType; + } + if (typeof config.onDownloadProgress === "function") { + request.addEventListener("progress", progressEventReducer(config.onDownloadProgress, true)); + } + if (typeof config.onUploadProgress === "function" && request.upload) { + request.upload.addEventListener("progress", progressEventReducer(config.onUploadProgress)); + } + if (config.cancelToken || config.signal) { + onCanceled = (cancel) => { + if (!request) { + return; + } + reject(!cancel || cancel.type ? new CanceledError_default(null, config, request) : cancel); + request.abort(); + request = null; + }; + config.cancelToken && config.cancelToken.subscribe(onCanceled); + if (config.signal) { + config.signal.aborted ? onCanceled() : config.signal.addEventListener("abort", onCanceled); + } + } + const protocol = parseProtocol(fullPath); + if (protocol && browser_default.protocols.indexOf(protocol) === -1) { + reject(new AxiosError_default("Unsupported protocol " + protocol + ":", AxiosError_default.ERR_BAD_REQUEST, config)); + return; + } + request.send(requestData || null); + }); +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/adapters/adapters.js +var knownAdapters = { + http: null_default, + xhr: xhr_default +}; +utils_default.forEach(knownAdapters, (fn, value) => { + if (fn) { + try { + Object.defineProperty(fn, "name", { value }); + } catch (e) { + } + Object.defineProperty(fn, "adapterName", { value }); + } +}); +var renderReason = (reason) => `- ${reason}`; +var isResolvedHandle = (adapter) => utils_default.isFunction(adapter) || adapter === null || adapter === false; +var adapters_default = { + getAdapter: (adapters) => { + adapters = utils_default.isArray(adapters) ? adapters : [adapters]; + const { length } = adapters; + let nameOrAdapter; + let adapter; + const rejectedReasons = {}; + for (let i = 0; i < length; i++) { + nameOrAdapter = adapters[i]; + let id; + adapter = nameOrAdapter; + if (!isResolvedHandle(nameOrAdapter)) { + adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()]; + if (adapter === void 0) { + throw new AxiosError_default(`Unknown adapter '${id}'`); + } + } + if (adapter) { + break; + } + rejectedReasons[id || "#" + i] = adapter; + } + if (!adapter) { + const reasons = Object.entries(rejectedReasons).map( + ([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build") + ); + let s = length ? reasons.length > 1 ? "since :\n" + reasons.map(renderReason).join("\n") : " " + renderReason(reasons[0]) : "as no adapter specified"; + throw new AxiosError_default( + `There is no suitable adapter to dispatch the request ` + s, + "ERR_NOT_SUPPORT" + ); + } + return adapter; + }, + adapters: knownAdapters +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/dispatchRequest.js +function throwIfCancellationRequested(config) { + if (config.cancelToken) { + config.cancelToken.throwIfRequested(); + } + if (config.signal && config.signal.aborted) { + throw new CanceledError_default(null, config); + } +} +function dispatchRequest(config) { + throwIfCancellationRequested(config); + config.headers = AxiosHeaders_default.from(config.headers); + config.data = transformData.call( + config, + config.transformRequest + ); + if (["post", "put", "patch"].indexOf(config.method) !== -1) { + config.headers.setContentType("application/x-www-form-urlencoded", false); + } + const adapter = adapters_default.getAdapter(config.adapter || defaults_default.adapter); + return adapter(config).then(function onAdapterResolution(response) { + throwIfCancellationRequested(config); + response.data = transformData.call( + config, + config.transformResponse, + response + ); + response.headers = AxiosHeaders_default.from(response.headers); + return response; + }, function onAdapterRejection(reason) { + if (!isCancel(reason)) { + throwIfCancellationRequested(config); + if (reason && reason.response) { + reason.response.data = transformData.call( + config, + config.transformResponse, + reason.response + ); + reason.response.headers = AxiosHeaders_default.from(reason.response.headers); + } + } + return Promise.reject(reason); + }); +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/mergeConfig.js +var headersToObject = (thing) => thing instanceof AxiosHeaders_default ? thing.toJSON() : thing; +function mergeConfig(config1, config2) { + config2 = config2 || {}; + const config = {}; + function getMergedValue(target, source, caseless) { + if (utils_default.isPlainObject(target) && utils_default.isPlainObject(source)) { + return utils_default.merge.call({ caseless }, target, source); + } else if (utils_default.isPlainObject(source)) { + return utils_default.merge({}, source); + } else if (utils_default.isArray(source)) { + return source.slice(); + } + return source; + } + function mergeDeepProperties(a, b, caseless) { + if (!utils_default.isUndefined(b)) { + return getMergedValue(a, b, caseless); + } else if (!utils_default.isUndefined(a)) { + return getMergedValue(void 0, a, caseless); + } + } + function valueFromConfig2(a, b) { + if (!utils_default.isUndefined(b)) { + return getMergedValue(void 0, b); + } + } + function defaultToConfig2(a, b) { + if (!utils_default.isUndefined(b)) { + return getMergedValue(void 0, b); + } else if (!utils_default.isUndefined(a)) { + return getMergedValue(void 0, a); + } + } + function mergeDirectKeys(a, b, prop) { + if (prop in config2) { + return getMergedValue(a, b); + } else if (prop in config1) { + return getMergedValue(void 0, a); + } + } + const mergeMap = { + url: valueFromConfig2, + method: valueFromConfig2, + data: valueFromConfig2, + baseURL: defaultToConfig2, + transformRequest: defaultToConfig2, + transformResponse: defaultToConfig2, + paramsSerializer: defaultToConfig2, + timeout: defaultToConfig2, + timeoutMessage: defaultToConfig2, + withCredentials: defaultToConfig2, + adapter: defaultToConfig2, + responseType: defaultToConfig2, + xsrfCookieName: defaultToConfig2, + xsrfHeaderName: defaultToConfig2, + onUploadProgress: defaultToConfig2, + onDownloadProgress: defaultToConfig2, + decompress: defaultToConfig2, + maxContentLength: defaultToConfig2, + maxBodyLength: defaultToConfig2, + beforeRedirect: defaultToConfig2, + transport: defaultToConfig2, + httpAgent: defaultToConfig2, + httpsAgent: defaultToConfig2, + cancelToken: defaultToConfig2, + socketPath: defaultToConfig2, + responseEncoding: defaultToConfig2, + validateStatus: mergeDirectKeys, + headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true) + }; + utils_default.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) { + const merge2 = mergeMap[prop] || mergeDeepProperties; + const configValue = merge2(config1[prop], config2[prop], prop); + utils_default.isUndefined(configValue) && merge2 !== mergeDirectKeys || (config[prop] = configValue); + }); + return config; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/env/data.js +var VERSION = "1.6.0"; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/validator.js +var validators = {}; +["object", "boolean", "number", "function", "string", "symbol"].forEach((type, i) => { + validators[type] = function validator(thing) { + return typeof thing === type || "a" + (i < 1 ? "n " : " ") + type; + }; +}); +var deprecatedWarnings = {}; +validators.transitional = function transitional(validator, version2, message) { + function formatMessage(opt, desc) { + return "[Axios v" + VERSION + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : ""); + } + return (value, opt, opts) => { + if (validator === false) { + throw new AxiosError_default( + formatMessage(opt, " has been removed" + (version2 ? " in " + version2 : "")), + AxiosError_default.ERR_DEPRECATED + ); + } + if (version2 && !deprecatedWarnings[opt]) { + deprecatedWarnings[opt] = true; + console.warn( + formatMessage( + opt, + " has been deprecated since v" + version2 + " and will be removed in the near future" + ) + ); + } + return validator ? validator(value, opt, opts) : true; + }; +}; +function assertOptions(options, schema, allowUnknown) { + if (typeof options !== "object") { + throw new AxiosError_default("options must be an object", AxiosError_default.ERR_BAD_OPTION_VALUE); + } + const keys = Object.keys(options); + let i = keys.length; + while (i-- > 0) { + const opt = keys[i]; + const validator = schema[opt]; + if (validator) { + const value = options[opt]; + const result = value === void 0 || validator(value, opt, options); + if (result !== true) { + throw new AxiosError_default("option " + opt + " must be " + result, AxiosError_default.ERR_BAD_OPTION_VALUE); + } + continue; + } + if (allowUnknown !== true) { + throw new AxiosError_default("Unknown option " + opt, AxiosError_default.ERR_BAD_OPTION); + } + } +} +var validator_default = { + assertOptions, + validators +}; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/Axios.js +var validators2 = validator_default.validators; +var Axios = class { + constructor(instanceConfig) { + this.defaults = instanceConfig; + this.interceptors = { + request: new InterceptorManager_default(), + response: new InterceptorManager_default() + }; + } + /** + * Dispatch a request + * + * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults) + * @param {?Object} config + * + * @returns {Promise} The Promise to be fulfilled + */ + request(configOrUrl, config) { + if (typeof configOrUrl === "string") { + config = config || {}; + config.url = configOrUrl; + } else { + config = configOrUrl || {}; + } + config = mergeConfig(this.defaults, config); + const { transitional: transitional2, paramsSerializer, headers } = config; + if (transitional2 !== void 0) { + validator_default.assertOptions(transitional2, { + silentJSONParsing: validators2.transitional(validators2.boolean), + forcedJSONParsing: validators2.transitional(validators2.boolean), + clarifyTimeoutError: validators2.transitional(validators2.boolean) + }, false); + } + if (paramsSerializer != null) { + if (utils_default.isFunction(paramsSerializer)) { + config.paramsSerializer = { + serialize: paramsSerializer + }; + } else { + validator_default.assertOptions(paramsSerializer, { + encode: validators2.function, + serialize: validators2.function + }, true); + } + } + config.method = (config.method || this.defaults.method || "get").toLowerCase(); + let contextHeaders = headers && utils_default.merge( + headers.common, + headers[config.method] + ); + headers && utils_default.forEach( + ["delete", "get", "head", "post", "put", "patch", "common"], + (method) => { + delete headers[method]; + } + ); + config.headers = AxiosHeaders_default.concat(contextHeaders, headers); + const requestInterceptorChain = []; + let synchronousRequestInterceptors = true; + this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { + if (typeof interceptor.runWhen === "function" && interceptor.runWhen(config) === false) { + return; + } + synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; + requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); + }); + const responseInterceptorChain = []; + this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { + responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); + }); + let promise; + let i = 0; + let len; + if (!synchronousRequestInterceptors) { + const chain = [dispatchRequest.bind(this), void 0]; + chain.unshift.apply(chain, requestInterceptorChain); + chain.push.apply(chain, responseInterceptorChain); + len = chain.length; + promise = Promise.resolve(config); + while (i < len) { + promise = promise.then(chain[i++], chain[i++]); + } + return promise; + } + len = requestInterceptorChain.length; + let newConfig = config; + i = 0; + while (i < len) { + const onFulfilled = requestInterceptorChain[i++]; + const onRejected = requestInterceptorChain[i++]; + try { + newConfig = onFulfilled(newConfig); + } catch (error) { + onRejected.call(this, error); + break; + } + } + try { + promise = dispatchRequest.call(this, newConfig); + } catch (error) { + return Promise.reject(error); + } + i = 0; + len = responseInterceptorChain.length; + while (i < len) { + promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]); + } + return promise; + } + getUri(config) { + config = mergeConfig(this.defaults, config); + const fullPath = buildFullPath(config.baseURL, config.url); + return buildURL(fullPath, config.params, config.paramsSerializer); + } +}; +utils_default.forEach(["delete", "get", "head", "options"], function forEachMethodNoData(method) { + Axios.prototype[method] = function(url, config) { + return this.request(mergeConfig(config || {}, { + method, + url, + data: (config || {}).data + })); + }; +}); +utils_default.forEach(["post", "put", "patch"], function forEachMethodWithData(method) { + function generateHTTPMethod(isForm) { + return function httpMethod(url, data, config) { + return this.request(mergeConfig(config || {}, { + method, + headers: isForm ? { + "Content-Type": "multipart/form-data" + } : {}, + url, + data + })); + }; + } + Axios.prototype[method] = generateHTTPMethod(); + Axios.prototype[method + "Form"] = generateHTTPMethod(true); +}); +var Axios_default = Axios; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/cancel/CancelToken.js +var CancelToken = class _CancelToken { + constructor(executor) { + if (typeof executor !== "function") { + throw new TypeError("executor must be a function."); + } + let resolvePromise; + this.promise = new Promise(function promiseExecutor(resolve) { + resolvePromise = resolve; + }); + const token = this; + this.promise.then((cancel) => { + if (!token._listeners) + return; + let i = token._listeners.length; + while (i-- > 0) { + token._listeners[i](cancel); + } + token._listeners = null; + }); + this.promise.then = (onfulfilled) => { + let _resolve; + const promise = new Promise((resolve) => { + token.subscribe(resolve); + _resolve = resolve; + }).then(onfulfilled); + promise.cancel = function reject() { + token.unsubscribe(_resolve); + }; + return promise; + }; + executor(function cancel(message, config, request) { + if (token.reason) { + return; + } + token.reason = new CanceledError_default(message, config, request); + resolvePromise(token.reason); + }); + } + /** + * Throws a `CanceledError` if cancellation has been requested. + */ + throwIfRequested() { + if (this.reason) { + throw this.reason; + } + } + /** + * Subscribe to the cancel signal + */ + subscribe(listener) { + if (this.reason) { + listener(this.reason); + return; + } + if (this._listeners) { + this._listeners.push(listener); + } else { + this._listeners = [listener]; + } + } + /** + * Unsubscribe from the cancel signal + */ + unsubscribe(listener) { + if (!this._listeners) { + return; + } + const index = this._listeners.indexOf(listener); + if (index !== -1) { + this._listeners.splice(index, 1); + } + } + /** + * Returns an object that contains a new `CancelToken` and a function that, when called, + * cancels the `CancelToken`. + */ + static source() { + let cancel; + const token = new _CancelToken(function executor(c) { + cancel = c; + }); + return { + token, + cancel + }; + } +}; +var CancelToken_default = CancelToken; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/spread.js +function spread(callback) { + return function wrap(arr) { + return callback.apply(null, arr); + }; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/isAxiosError.js +function isAxiosError(payload) { + return utils_default.isObject(payload) && payload.isAxiosError === true; +} + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/HttpStatusCode.js +var HttpStatusCode = { + Continue: 100, + SwitchingProtocols: 101, + Processing: 102, + EarlyHints: 103, + Ok: 200, + Created: 201, + Accepted: 202, + NonAuthoritativeInformation: 203, + NoContent: 204, + ResetContent: 205, + PartialContent: 206, + MultiStatus: 207, + AlreadyReported: 208, + ImUsed: 226, + MultipleChoices: 300, + MovedPermanently: 301, + Found: 302, + SeeOther: 303, + NotModified: 304, + UseProxy: 305, + Unused: 306, + TemporaryRedirect: 307, + PermanentRedirect: 308, + BadRequest: 400, + Unauthorized: 401, + PaymentRequired: 402, + Forbidden: 403, + NotFound: 404, + MethodNotAllowed: 405, + NotAcceptable: 406, + ProxyAuthenticationRequired: 407, + RequestTimeout: 408, + Conflict: 409, + Gone: 410, + LengthRequired: 411, + PreconditionFailed: 412, + PayloadTooLarge: 413, + UriTooLong: 414, + UnsupportedMediaType: 415, + RangeNotSatisfiable: 416, + ExpectationFailed: 417, + ImATeapot: 418, + MisdirectedRequest: 421, + UnprocessableEntity: 422, + Locked: 423, + FailedDependency: 424, + TooEarly: 425, + UpgradeRequired: 426, + PreconditionRequired: 428, + TooManyRequests: 429, + RequestHeaderFieldsTooLarge: 431, + UnavailableForLegalReasons: 451, + InternalServerError: 500, + NotImplemented: 501, + BadGateway: 502, + ServiceUnavailable: 503, + GatewayTimeout: 504, + HttpVersionNotSupported: 505, + VariantAlsoNegotiates: 506, + InsufficientStorage: 507, + LoopDetected: 508, + NotExtended: 510, + NetworkAuthenticationRequired: 511 +}; +Object.entries(HttpStatusCode).forEach(([key, value]) => { + HttpStatusCode[value] = key; +}); +var HttpStatusCode_default = HttpStatusCode; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/axios.js +function createInstance(defaultConfig) { + const context = new Axios_default(defaultConfig); + const instance = bind(Axios_default.prototype.request, context); + utils_default.extend(instance, Axios_default.prototype, context, { allOwnKeys: true }); + utils_default.extend(instance, context, null, { allOwnKeys: true }); + instance.create = function create(instanceConfig) { + return createInstance(mergeConfig(defaultConfig, instanceConfig)); + }; + return instance; +} +var axios = createInstance(defaults_default); +axios.Axios = Axios_default; +axios.CanceledError = CanceledError_default; +axios.CancelToken = CancelToken_default; +axios.isCancel = isCancel; +axios.VERSION = VERSION; +axios.toFormData = toFormData_default; +axios.AxiosError = AxiosError_default; +axios.Cancel = axios.CanceledError; +axios.all = function all(promises) { + return Promise.all(promises); +}; +axios.spread = spread; +axios.isAxiosError = isAxiosError; +axios.mergeConfig = mergeConfig; +axios.AxiosHeaders = AxiosHeaders_default; +axios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing); +axios.getAdapter = adapters_default.getAdapter; +axios.HttpStatusCode = HttpStatusCode_default; +axios.default = axios; +var axios_default = axios; + +// node_modules/.pnpm/axios@1.6.0/node_modules/axios/index.js +var { + Axios: Axios2, + AxiosError: AxiosError2, + CanceledError: CanceledError2, + isCancel: isCancel2, + CancelToken: CancelToken2, + VERSION: VERSION2, + all: all2, + Cancel, + isAxiosError: isAxiosError2, + spread: spread2, + toFormData: toFormData2, + AxiosHeaders: AxiosHeaders2, + HttpStatusCode: HttpStatusCode2, + formToJSON, + getAdapter, + mergeConfig: mergeConfig2 +} = axios_default; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/createWebWorkerPromise.js +var import_webworker_promise = __toESM(require_src(), 1); +async function createWebWorkerPromise(existingWorker, pipelineWorkerUrl3) { + let workerPromise; + if (existingWorker != null) { + const itkWebWorker2 = existingWorker; + if (itkWebWorker2.workerPromise !== void 0) { + workerPromise = itkWebWorker2.workerPromise; + } else { + workerPromise = new import_webworker_promise.default(existingWorker); + } + return await Promise.resolve({ webworkerPromise: workerPromise, worker: existingWorker }); + } + const workerUrl = typeof pipelineWorkerUrl3 === "undefined" ? itkConfig_default.pipelineWorkerUrl : pipelineWorkerUrl3; + let worker = null; + const webWorkersUrl = itkConfig_default.webWorkersUrl; + if (typeof webWorkersUrl !== "undefined") { + console.warn("itkConfig webWorkersUrl is deprecated. Please use pipelineWorkerUrl with the full path to the pipeline worker."); + const min = "min."; + const webWorkerString = webWorkersUrl; + if (webWorkerString.startsWith("http")) { + const response = await axios_default.get(`${webWorkerString}/bundles/pipeline.${min}worker.js`, { responseType: "blob" }); + const workerObjectUrl = URL.createObjectURL(response.data); + worker = new Worker(workerObjectUrl, { type: "module" }); + } else { + worker = new Worker(`${webWorkerString}/bundles/pipeline.${min}worker.js`, { type: "module" }); + } + } else if (workerUrl === null) { + worker = new Worker(new URL("./web-workers/itk-wasm-pipeline.worker.js", import.meta.url), { type: "module" }); + } else { + if (workerUrl.startsWith("http")) { + const response = await axios_default.get(workerUrl, { responseType: "blob" }); + const workerObjectUrl = URL.createObjectURL(response.data); + worker = new Worker(workerObjectUrl, { type: "module" }); + } else { + worker = new Worker(workerUrl, { type: "module" }); + } + } + const webworkerPromise = new import_webworker_promise.default(worker); + const itkWebWorker = worker; + itkWebWorker.workerPromise = webworkerPromise; + return { webworkerPromise, worker: itkWebWorker }; +} +var createWebWorkerPromise_default = createWebWorkerPromise; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/pipeline-worker-url.js +var pipelineWorkerUrl; +function getPipelineWorkerUrl() { + return pipelineWorkerUrl; +} + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/pipelines-base-url.js +var pipelinesBaseUrl; +function getPipelinesBaseUrl() { + return pipelinesBaseUrl; +} + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/io/getFileExtension.js +function getFileExtension(filePath) { + let extension = filePath.slice((filePath.lastIndexOf(".") - 1 >>> 0) + 2); + if (extension.toLowerCase() === "gz") { + const index = filePath.slice(0, -3).lastIndexOf("."); + extension = filePath.slice((index - 1 >>> 0) + 2); + } else if (extension.toLowerCase() === "cbor") { + const index = filePath.slice(0, -5).lastIndexOf("."); + extension = filePath.slice((index - 1 >>> 0) + 2); + } else if (extension.toLowerCase() === "zst") { + const index = filePath.slice(0, -10).lastIndexOf("."); + extension = filePath.slice((index - 1 >>> 0) + 2); + } else if (extension.toLowerCase() === "zip") { + const index = filePath.slice(0, -4).lastIndexOf("."); + extension = filePath.slice((index - 1 >>> 0) + 2); + } + return extension; +} +var getFileExtension_default = getFileExtension; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/internal/imageTransferables.js +function imageTransferables(image) { + return [ + image.data, + image.direction + ]; +} +var imageTransferables_default = imageTransferables; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/internal/meshTransferables.js +function meshTransferables(mesh) { + return [ + mesh.points, + mesh.pointData, + mesh.cells, + mesh.cellData + ]; +} +var meshTransferables_default = meshTransferables; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/internal/loadEmscriptenModuleMainThread.js +async function loadEmscriptenModuleMainThread(moduleRelativePathOrURL, baseUrl) { + let modulePrefix = "unknown"; + if (typeof moduleRelativePathOrURL !== "string") { + modulePrefix = moduleRelativePathOrURL.href; + } else if (moduleRelativePathOrURL.startsWith("http")) { + modulePrefix = moduleRelativePathOrURL; + } else { + modulePrefix = `${baseUrl}/${moduleRelativePathOrURL}`; + } + if (modulePrefix.endsWith(".js")) { + modulePrefix = modulePrefix.substring(0, modulePrefix.length - 3); + } + if (modulePrefix.endsWith(".wasm")) { + modulePrefix = modulePrefix.substring(0, modulePrefix.length - 5); + } + const wasmBinaryPath = `${modulePrefix}.wasm`; + const response = await axios_default.get(wasmBinaryPath, { responseType: "arraybuffer" }); + const wasmBinary = response.data; + const fullModulePath = `${modulePrefix}.js`; + const result = await import( + /* webpackIgnore: true */ + /* @vite-ignore */ + fullModulePath + ); + const instantiated = result.default({ wasmBinary }); + return instantiated; +} +var loadEmscriptenModuleMainThread_default = loadEmscriptenModuleMainThread; + +// node_modules/.pnpm/wasm-feature-detect@1.6.1/node_modules/wasm-feature-detect/dist/esm/index.js +var simd = async () => WebAssembly.validate(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11])); + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/pipeline/internal/runPipelineEmscripten.js +var haveSharedArrayBuffer2 = typeof globalThis.SharedArrayBuffer === "function"; +var encoder = new TextEncoder(); +var decoder = new TextDecoder("utf-8"); +function readFileSharedArray(emscriptenModule, path) { + const opts = { flags: "r", encoding: "binary" }; + const stream = emscriptenModule.fs_open(path, opts.flags); + const stat = emscriptenModule.fs_stat(path); + const length = stat.size; + let arrayBufferData = null; + if (haveSharedArrayBuffer2) { + arrayBufferData = new SharedArrayBuffer(length); + } else { + arrayBufferData = new ArrayBuffer(length); + } + const array = new Uint8Array(arrayBufferData); + emscriptenModule.fs_read(stream, array, 0, length, 0); + emscriptenModule.fs_close(stream); + return array; +} +function memoryUint8SharedArray(emscriptenModule, byteOffset, length) { + let arrayBufferData = null; + if (haveSharedArrayBuffer2) { + arrayBufferData = new SharedArrayBuffer(length); + } else { + arrayBufferData = new ArrayBuffer(length); + } + const array = new Uint8Array(arrayBufferData); + const dataArrayView = new Uint8Array(emscriptenModule.HEAPU8.buffer, byteOffset, length); + array.set(dataArrayView); + return array; +} +function setPipelineModuleInputArray(emscriptenModule, dataArray, inputIndex, subIndex) { + let dataPtr = 0; + if (dataArray !== null) { + dataPtr = emscriptenModule.ccall("itk_wasm_input_array_alloc", "number", ["number", "number", "number", "number"], [0, inputIndex, subIndex, dataArray.buffer.byteLength]); + emscriptenModule.HEAPU8.set(new Uint8Array(dataArray.buffer), dataPtr); + } + return dataPtr; +} +function setPipelineModuleInputJSON(emscriptenModule, dataObject, inputIndex) { + const dataJSON = JSON.stringify(dataObject); + const jsonPtr = emscriptenModule.ccall("itk_wasm_input_json_alloc", "number", ["number", "number", "number"], [0, inputIndex, dataJSON.length]); + emscriptenModule.writeAsciiToMemory(dataJSON, jsonPtr, false); +} +function getPipelineModuleOutputArray(emscriptenModule, outputIndex, subIndex, componentType) { + const dataPtr = emscriptenModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, outputIndex, subIndex]); + const dataSize = emscriptenModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, outputIndex, subIndex]); + const dataUint8 = memoryUint8SharedArray(emscriptenModule, dataPtr, dataSize); + const data = bufferToTypedArray_default(componentType, dataUint8.buffer); + return data; +} +function getPipelineModuleOutputJSON(emscriptenModule, outputIndex) { + const jsonPtr = emscriptenModule.ccall("itk_wasm_output_json_address", "number", ["number", "number"], [0, outputIndex]); + const dataJSON = emscriptenModule.AsciiToString(jsonPtr); + const dataObject = JSON.parse(dataJSON); + return dataObject; +} +function runPipelineEmscripten(pipelineModule, args, outputs, inputs) { + if (!(inputs == null) && inputs.length > 0) { + inputs.forEach(function(input, index) { + var _a; + switch (input.type) { + case InterfaceTypes_default.TextStream: { + const dataArray = encoder.encode(input.data.data); + const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0); + const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` }; + setPipelineModuleInputJSON(pipelineModule, dataJSON, index); + break; + } + case InterfaceTypes_default.JsonCompatible: { + const dataArray = encoder.encode(JSON.stringify(input.data)); + const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0); + const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` }; + setPipelineModuleInputJSON(pipelineModule, dataJSON, index); + break; + } + case InterfaceTypes_default.BinaryStream: { + const dataArray = input.data.data; + const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0); + const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` }; + setPipelineModuleInputJSON(pipelineModule, dataJSON, index); + break; + } + case InterfaceTypes_default.TextFile: { + pipelineModule.fs_writeFile(input.data.path, input.data.data); + break; + } + case InterfaceTypes_default.BinaryFile: { + pipelineModule.fs_writeFile(input.data.path, input.data.data); + break; + } + case InterfaceTypes_default.Image: { + const image = input.data; + const dataPtr = setPipelineModuleInputArray(pipelineModule, image.data, index, 0); + const directionPtr = setPipelineModuleInputArray(pipelineModule, image.direction, index, 1); + const metadata = typeof ((_a = image.metadata) === null || _a === void 0 ? void 0 : _a.entries) !== "undefined" ? JSON.stringify(Array.from(image.metadata.entries())) : "[]"; + const imageJSON = { + imageType: image.imageType, + name: image.name, + origin: image.origin, + spacing: image.spacing, + direction: `data:application/vnd.itk.address,0:${directionPtr}`, + size: image.size, + data: `data:application/vnd.itk.address,0:${dataPtr}`, + metadata + }; + setPipelineModuleInputJSON(pipelineModule, imageJSON, index); + break; + } + case InterfaceTypes_default.Mesh: { + const mesh = input.data; + const pointsPtr = setPipelineModuleInputArray(pipelineModule, mesh.points, index, 0); + const cellsPtr = setPipelineModuleInputArray(pipelineModule, mesh.cells, index, 1); + const pointDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.pointData, index, 2); + const cellDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.cellData, index, 3); + const meshJSON = { + meshType: mesh.meshType, + name: mesh.name, + numberOfPoints: mesh.numberOfPoints, + points: `data:application/vnd.itk.address,0:${pointsPtr}`, + numberOfCells: mesh.numberOfCells, + cells: `data:application/vnd.itk.address,0:${cellsPtr}`, + cellBufferSize: mesh.cellBufferSize, + numberOfPointPixels: mesh.numberOfPointPixels, + pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`, + numberOfCellPixels: mesh.numberOfCellPixels, + cellData: `data:application/vnd.itk.address,0:${cellDataPtr}` + }; + setPipelineModuleInputJSON(pipelineModule, meshJSON, index); + break; + } + case InterfaceTypes_default.PolyData: { + const polyData = input.data; + const pointsPtr = setPipelineModuleInputArray(pipelineModule, polyData.points, index, 0); + const verticesPtr = setPipelineModuleInputArray(pipelineModule, polyData.vertices, index, 1); + const linesPtr = setPipelineModuleInputArray(pipelineModule, polyData.lines, index, 2); + const polygonsPtr = setPipelineModuleInputArray(pipelineModule, polyData.polygons, index, 3); + const triangleStripsPtr = setPipelineModuleInputArray(pipelineModule, polyData.triangleStrips, index, 4); + const pointDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 5); + const cellDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 6); + const polyDataJSON = { + polyDataType: polyData.polyDataType, + name: polyData.name, + numberOfPoints: polyData.numberOfPoints, + points: `data:application/vnd.itk.address,0:${pointsPtr}`, + verticesBufferSize: polyData.verticesBufferSize, + vertices: `data:application/vnd.itk.address,0:${verticesPtr}`, + linesBufferSize: polyData.linesBufferSize, + lines: `data:application/vnd.itk.address,0:${linesPtr}`, + polygonsBufferSize: polyData.polygonsBufferSize, + polygons: `data:application/vnd.itk.address,0:${polygonsPtr}`, + triangleStripsBufferSize: polyData.triangleStripsBufferSize, + triangleStrips: `data:application/vnd.itk.address,0:${triangleStripsPtr}`, + numberOfPointPixels: polyData.numberOfPointPixels, + pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`, + numberOfCellPixels: polyData.numberOfCellPixels, + cellData: `data:application/vnd.itk.address,0:${cellDataPtr}` + }; + setPipelineModuleInputJSON(pipelineModule, polyDataJSON, index); + break; + } + case IOTypes_default.Text: { + pipelineModule.fs_writeFile(input.path, input.data); + break; + } + case IOTypes_default.Binary: { + pipelineModule.fs_writeFile(input.path, input.data); + break; + } + case IOTypes_default.Image: { + const image = input.data; + const imageJSON = { + imageType: image.imageType, + name: image.name, + origin: image.origin, + spacing: image.spacing, + direction: "data:application/vnd.itk.path,data/direction.raw", + size: image.size, + data: "data:application/vnd.itk.path,data/data.raw" + }; + pipelineModule.fs_mkdirs(`${input.path}/data`); + pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(imageJSON)); + if (image.data === null) { + throw Error("image.data is null"); + } + pipelineModule.fs_writeFile(`${input.path}/data/data.raw`, new Uint8Array(image.data.buffer)); + pipelineModule.fs_writeFile(`${input.path}/data/direction.raw`, new Uint8Array(image.direction.buffer)); + break; + } + case IOTypes_default.Mesh: { + const mesh = input.data; + const meshJSON = { + meshType: mesh.meshType, + name: mesh.name, + numberOfPoints: mesh.numberOfPoints, + points: "data:application/vnd.itk.path,data/points.raw", + numberOfPointPixels: mesh.numberOfPointPixels, + pointData: "data:application/vnd.itk.path,data/pointData.raw", + numberOfCells: mesh.numberOfCells, + cells: "data:application/vnd.itk.path,data/cells.raw", + numberOfCellPixels: mesh.numberOfCellPixels, + cellData: "data:application/vnd.itk.path,data/cellData.raw", + cellBufferSize: mesh.cellBufferSize + }; + pipelineModule.fs_mkdirs(`${input.path}/data`); + pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(meshJSON)); + if (meshJSON.numberOfPoints > 0) { + if (mesh.points === null) { + throw Error("mesh.points is null"); + } + pipelineModule.fs_writeFile(`${input.path}/data/points.raw`, new Uint8Array(mesh.points.buffer)); + } + if (meshJSON.numberOfPointPixels > 0) { + if (mesh.pointData === null) { + throw Error("mesh.pointData is null"); + } + pipelineModule.fs_writeFile(`${input.path}/data/pointData.raw`, new Uint8Array(mesh.pointData.buffer)); + } + if (meshJSON.numberOfCells > 0) { + if (mesh.cells === null) { + throw Error("mesh.cells is null"); + } + pipelineModule.fs_writeFile(`${input.path}/data/cells.raw`, new Uint8Array(mesh.cells.buffer)); + } + if (meshJSON.numberOfCellPixels > 0) { + if (mesh.cellData === null) { + throw Error("mesh.cellData is null"); + } + pipelineModule.fs_writeFile(`${input.path}/data/cellData.raw`, new Uint8Array(mesh.cellData.buffer)); + } + break; + } + default: + throw Error("Unsupported input InterfaceType"); + } + }); + } + pipelineModule.resetModuleStdout(); + pipelineModule.resetModuleStderr(); + const stackPtr = pipelineModule.stackSave(); + let returnValue = 0; + try { + returnValue = pipelineModule.callMain(args.slice()); + } catch (exception) { + if (typeof exception === "number") { + console.log("Exception while running pipeline:"); + console.log("stdout:", pipelineModule.getModuleStdout()); + console.error("stderr:", pipelineModule.getModuleStderr()); + if (typeof pipelineModule.getExceptionMessage !== "undefined") { + console.error("exception:", pipelineModule.getExceptionMessage(exception)); + } else { + console.error("Build module in Debug mode for exception message information."); + } + } + throw exception; + } finally { + pipelineModule.stackRestore(stackPtr); + } + const stdout = pipelineModule.getModuleStdout(); + const stderr = pipelineModule.getModuleStderr(); + const populatedOutputs = []; + if (!(outputs == null) && outputs.length > 0 && returnValue === 0) { + outputs.forEach(function(output, index) { + let outputData = null; + switch (output.type) { + case InterfaceTypes_default.TextStream: { + const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]); + const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]); + const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize); + outputData = { data: decoder.decode(dataArrayView) }; + break; + } + case InterfaceTypes_default.JsonCompatible: { + const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]); + const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]); + const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize); + outputData = JSON.parse(decoder.decode(dataArrayView)); + break; + } + case InterfaceTypes_default.BinaryStream: { + const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]); + const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]); + outputData = { data: memoryUint8SharedArray(pipelineModule, dataPtr, dataSize) }; + break; + } + case InterfaceTypes_default.TextFile: { + outputData = { path: output.data.path, data: pipelineModule.fs_readFile(output.data.path, { encoding: "utf8" }) }; + break; + } + case InterfaceTypes_default.BinaryFile: { + outputData = { path: output.data.path, data: readFileSharedArray(pipelineModule, output.data.path) }; + break; + } + case InterfaceTypes_default.Image: { + const image = getPipelineModuleOutputJSON(pipelineModule, index); + image.data = getPipelineModuleOutputArray(pipelineModule, index, 0, image.imageType.componentType); + image.direction = getPipelineModuleOutputArray(pipelineModule, index, 1, float_types_default.Float64); + image.metadata = new Map(image.metadata); + outputData = image; + break; + } + case InterfaceTypes_default.Mesh: { + const mesh = getPipelineModuleOutputJSON(pipelineModule, index); + if (mesh.numberOfPoints > 0) { + mesh.points = getPipelineModuleOutputArray(pipelineModule, index, 0, mesh.meshType.pointComponentType); + } else { + mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0)); + } + if (mesh.numberOfCells > 0) { + mesh.cells = getPipelineModuleOutputArray(pipelineModule, index, 1, mesh.meshType.cellComponentType); + } else { + mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0)); + } + if (mesh.numberOfPointPixels > 0) { + mesh.pointData = getPipelineModuleOutputArray(pipelineModule, index, 2, mesh.meshType.pointPixelComponentType); + } else { + mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0)); + } + if (mesh.numberOfCellPixels > 0) { + mesh.cellData = getPipelineModuleOutputArray(pipelineModule, index, 3, mesh.meshType.cellPixelComponentType); + } else { + mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0)); + } + outputData = mesh; + break; + } + case InterfaceTypes_default.PolyData: { + const polyData = getPipelineModuleOutputJSON(pipelineModule, index); + if (polyData.numberOfPoints > 0) { + polyData.points = getPipelineModuleOutputArray(pipelineModule, index, 0, float_types_default.Float32); + } else { + polyData.points = new Float32Array(); + } + if (polyData.verticesBufferSize > 0) { + polyData.vertices = getPipelineModuleOutputArray(pipelineModule, index, 1, int_types_default.UInt32); + } else { + polyData.vertices = new Uint32Array(); + } + if (polyData.linesBufferSize > 0) { + polyData.lines = getPipelineModuleOutputArray(pipelineModule, index, 2, int_types_default.UInt32); + } else { + polyData.lines = new Uint32Array(); + } + if (polyData.polygonsBufferSize > 0) { + polyData.polygons = getPipelineModuleOutputArray(pipelineModule, index, 3, int_types_default.UInt32); + } else { + polyData.polygons = new Uint32Array(); + } + if (polyData.triangleStripsBufferSize > 0) { + polyData.triangleStrips = getPipelineModuleOutputArray(pipelineModule, index, 4, int_types_default.UInt32); + } else { + polyData.triangleStrips = new Uint32Array(); + } + if (polyData.numberOfPointPixels > 0) { + polyData.pointData = getPipelineModuleOutputArray(pipelineModule, index, 5, polyData.polyDataType.pointPixelComponentType); + } else { + polyData.pointData = bufferToTypedArray_default(polyData.polyDataType.pointPixelComponentType, new ArrayBuffer(0)); + } + if (polyData.numberOfCellPixels > 0) { + polyData.cellData = getPipelineModuleOutputArray(pipelineModule, index, 6, polyData.polyDataType.cellPixelComponentType); + } else { + polyData.cellData = bufferToTypedArray_default(polyData.polyDataType.cellPixelComponentType, new ArrayBuffer(0)); + } + outputData = polyData; + break; + } + case IOTypes_default.Text: { + if (typeof output.path === "undefined") { + throw new Error("output.path not defined"); + } + outputData = pipelineModule.fs_readFile(output.path, { encoding: "utf8" }); + break; + } + case IOTypes_default.Binary: { + if (typeof output.path === "undefined") { + throw new Error("output.path not defined"); + } + outputData = readFileSharedArray(pipelineModule, output.path); + break; + } + case IOTypes_default.Image: { + if (typeof output.path === "undefined") { + throw new Error("output.path not defined"); + } + const imageJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" }); + const image = JSON.parse(imageJSON); + const dataUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/data.raw`); + image.data = bufferToTypedArray_default(image.imageType.componentType, dataUint8.buffer); + const directionUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/direction.raw`); + image.direction = bufferToTypedArray_default(float_types_default.Float64, directionUint8.buffer); + outputData = image; + break; + } + case IOTypes_default.Mesh: { + if (typeof output.path === "undefined") { + throw new Error("output.path not defined"); + } + const meshJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" }); + const mesh = JSON.parse(meshJSON); + if (mesh.numberOfPoints > 0) { + const dataUint8Points = readFileSharedArray(pipelineModule, `${output.path}/data/points.raw`); + mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, dataUint8Points.buffer); + } else { + mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0)); + } + if (mesh.numberOfPointPixels > 0) { + const dataUint8PointData = readFileSharedArray(pipelineModule, `${output.path}/data/pointData.raw`); + mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, dataUint8PointData.buffer); + } else { + mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0)); + } + if (mesh.numberOfCells > 0) { + const dataUint8Cells = readFileSharedArray(pipelineModule, `${output.path}/data/cells.raw`); + mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, dataUint8Cells.buffer); + } else { + mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0)); + } + if (mesh.numberOfCellPixels > 0) { + const dataUint8CellData = readFileSharedArray(pipelineModule, `${output.path}/data/cellData.raw`); + mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, dataUint8CellData.buffer); + } else { + mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0)); + } + outputData = mesh; + break; + } + default: + throw Error("Unsupported output InterfaceType"); + } + const populatedOutput = { + type: output.type, + data: outputData + }; + populatedOutputs.push(populatedOutput); + }); + } + return { returnValue, stdout, stderr, outputs: populatedOutputs }; +} +var runPipelineEmscripten_default = runPipelineEmscripten; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/pipeline/runPipeline.js +var pipelineToModule = /* @__PURE__ */ new Map(); +async function loadPipelineModule(pipelinePath) { + let moduleRelativePathOrURL = pipelinePath; + let pipeline = pipelinePath; + if (typeof pipelinePath !== "string") { + moduleRelativePathOrURL = new URL(pipelinePath.href); + pipeline = moduleRelativePathOrURL.href; + } + if (pipelineToModule.has(pipeline)) { + return pipelineToModule.get(pipeline); + } else { + const pipelineModule = await loadEmscriptenModuleMainThread_default(pipelinePath, itkConfig_default.pipelinesUrl); + pipelineToModule.set(pipeline, pipelineModule); + return pipelineModule; + } +} +async function runPipeline(webWorker, pipelinePath, args, outputs, inputs, options) { + var _a, _b; + if (!await simd()) { + const simdErrorMessage = "WebAssembly SIMD support is required -- please update your browser."; + alert(simdErrorMessage); + throw new Error(simdErrorMessage); + } + if (webWorker === false) { + const pipelineModule = await loadPipelineModule(pipelinePath.toString()); + const result2 = runPipelineEmscripten_default(pipelineModule, args, outputs, inputs); + return result2; + } + let worker = webWorker; + const pipelineWorkerUrl3 = (_a = options === null || options === void 0 ? void 0 : options.pipelineWorkerUrl) !== null && _a !== void 0 ? _a : null; + const pipelineWorkerUrlString = typeof pipelineWorkerUrl3 !== "string" && typeof (pipelineWorkerUrl3 === null || pipelineWorkerUrl3 === void 0 ? void 0 : pipelineWorkerUrl3.href) !== "undefined" ? pipelineWorkerUrl3.href : pipelineWorkerUrl3; + const { webworkerPromise, worker: usedWorker } = await createWebWorkerPromise_default(worker, pipelineWorkerUrlString); + worker = usedWorker; + const transferables = []; + if (!(inputs == null) && inputs.length > 0) { + inputs.forEach(function(input) { + if (input.type === InterfaceTypes_default.BinaryStream) { + const dataArray = input.data.data; + transferables.push(dataArray); + } else if (input.type === InterfaceTypes_default.BinaryFile) { + const dataArray = input.data.data; + transferables.push(dataArray); + } else if (input.type === InterfaceTypes_default.Image) { + const image = input.data; + if (image.data === null) { + throw Error("image data cannot be null"); + } + transferables.push(...imageTransferables_default(image)); + } else if (input.type === IOTypes_default.Binary) { + transferables.push(input.data); + } else if (input.type === IOTypes_default.Image) { + const image = input.data; + if (image.data === null) { + throw Error("image data cannot be null"); + } + transferables.push(...imageTransferables_default(image)); + } else if (input.type === IOTypes_default.Mesh) { + const mesh = input.data; + transferables.push(...meshTransferables_default(mesh)); + } + }); + } + const pipelineBaseUrl = (_b = options === null || options === void 0 ? void 0 : options.pipelineBaseUrl) !== null && _b !== void 0 ? _b : "pipelinesUrl"; + const pipelineBaseUrlString = typeof pipelineBaseUrl !== "string" && typeof (pipelineBaseUrl === null || pipelineBaseUrl === void 0 ? void 0 : pipelineBaseUrl.href) !== "undefined" ? pipelineBaseUrl.href : pipelineBaseUrl; + const result = await webworkerPromise.postMessage({ + operation: "runPipeline", + config: itkConfig_default, + pipelinePath: pipelinePath.toString(), + pipelineBaseUrl: pipelineBaseUrlString, + args, + outputs, + inputs + }, getTransferables_default(transferables)); + return { + returnValue: result.returnValue, + stdout: result.stdout, + stderr: result.stderr, + outputs: result.outputs, + webWorker: worker + }; +} +var runPipeline_default = runPipeline; + +// package.json +var package_default = { + name: "@itk-wasm/image-io", + version: "0.4.0", + description: "Input and output for scientific and medical image file formats.", + type: "module", + module: "./dist/index.js", + types: "./dist/index.d.ts", + exports: { + ".": { + types: "./dist/index.d.js", + browser: "./dist/index.js", + node: "./dist/index-node.js", + default: "./dist/index.js" + } + }, + scripts: { + start: "npm run copyShoelaceAssets && vite -c build/vite.config.js", + test: "npm run test:node && npm run test:browser", + "test:node": "ava", + "test:browser": "npm run test:browser:chrome && npm run test:browser:firefox", + "test:browser:firefox": "start-server-and-test rollup:start http-get://localhost:5004 cypress:runFirefox", + "test:browser:chrome": "start-server-and-test rollup:start http-get://localhost:5004 cypress:runChrome", + "test:browser:debug": "start-server-and-test rollup:start http-get://localhost:5004 cypress:open", + "cypress:open": "npx cypress open", + "cypress:runChrome": "npx cypress run --browser chrome", + "cypress:runFirefox": "npx cypress run --browser firefox", + build: "npm run build:tsc && npm run build:browser:webWorkers && npm run build:browser:workerEmbedded && npm run build:demo", + "build:browser:webWorkers": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/image-io-worker-embedded.js ./src/index-worker-embedded.ts", + "build:tsc": "tsc --pretty", + copyShoelaceAssets: "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", + "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build", + "rollup:start": "npm run copyShoelaceAssets && concurrently npm:rollup:dev npm:rollup:preview", + "rollup:dev": "vite build --config build/vite-rollup-watch.config.ts", + "rollup:preview": "vite preview --config build/vite-rollup-watch.config.ts" + }, + keywords: [ + "itk", + "wasm", + "webassembly", + "wasi" + ], + author: "", + license: "Apache-2.0", + dependencies: { + "itk-wasm": "^1.0.0-b.152" + }, + devDependencies: { + "@shoelace-style/shoelace": "^2.5.2", + "@types/node": "^20.2.5", + ava: "^5.3.1", + concurrently: "^8.2.1", + cypress: "^13.3.0", + esbuild: "^0.19.5", + shx: "^0.3.4", + "start-server-and-test": "^2.0.1", + typescript: "^5.0.4", + vite: "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" + }, + repository: { + type: "git", + url: "https://github.com/InsightSoftwareConsortium/itk-wasm" + }, + ava: { + files: [ + "test/node/**/*", + "!test/node/common.js" + ] + } +}; + +// src/pipelines-base-url.ts +var pipelinesBaseUrl2; +var defaultPipelinesBaseUrl = `https://cdn.jsdelivr.net/npm/@itk-wasm/image-io@${package_default.version}/dist/pipelines`; +function setPipelinesBaseUrl(baseUrl) { + pipelinesBaseUrl2 = baseUrl; +} +function getPipelinesBaseUrl2() { + if (typeof pipelinesBaseUrl2 !== "undefined") { + return pipelinesBaseUrl2; + } + const itkWasmPipelinesBaseUrl = getPipelinesBaseUrl(); + if (typeof itkWasmPipelinesBaseUrl !== "undefined") { + return itkWasmPipelinesBaseUrl; + } + return defaultPipelinesBaseUrl; +} + +// src/pipeline-worker-url.ts +var pipelineWorkerUrl2; +var defaultPipelineWorkerUrl = null; +function setPipelineWorkerUrl(workerUrl) { + pipelineWorkerUrl2 = workerUrl; +} +function getPipelineWorkerUrl2() { + if (typeof pipelineWorkerUrl2 !== "undefined") { + return pipelineWorkerUrl2; + } + const itkWasmPipelineWorkerUrl = getPipelineWorkerUrl(); + if (typeof itkWasmPipelineWorkerUrl !== "undefined") { + return itkWasmPipelineWorkerUrl; + } + return defaultPipelineWorkerUrl; +} + +// src/mime-to-image-io.ts +var mimeToImageIo = /* @__PURE__ */ new Map([ + ["image/jpeg", "jpeg"], + ["image/png", "png"], + ["image/tiff", "tiff"], + ["image/x-ms-bmp", "bmp"], + ["image/x-bmp", "bmp"], + ["image/bmp", "bmp"], + ["application/dicom", "gdcm"] +]); +var mime_to_image_io_default = mimeToImageIo; + +// src/extension-to-image-io.ts +var extensionToImageIo = /* @__PURE__ */ new Map([ + ["bmp", "bmp"], + ["dcm", "gdcm"], + ["gipl", "gipl"], + ["gipl.gz", "gipl"], + ["hdf5", "hdf5"], + ["jpg", "jpeg"], + ["jpeg", "jpeg"], + ["iwi", "wasm"], + ["iwi.cbor", "wasm"], + ["iwi.cbor.zst", "wasmZstd"], + ["lsm", "lsm"], + ["mnc", "mnc"], + ["mnc.gz", "mnc"], + ["mnc2", "mnc"], + ["mgh", "mgh"], + ["mgz", "mgh"], + ["mgh.gz", "mgh"], + ["mha", "meta"], + ["mhd", "meta"], + ["mrc", "mrc"], + ["nia", "nifti"], + ["nii", "nifti"], + ["nii.gz", "nifti"], + ["hdr", "nifti"], + ["nrrd", "nrrd"], + ["nhdr", "nrrd"], + ["png", "png"], + ["pic", "bioRad"], + ["tif", "tiff"], + ["tiff", "tiff"], + ["vtk", "vtk"], + ["isq", "scanco"], + ["aim", "scanco"], + ["fdf", "fdf"] +]); +var extension_to_image_io_default = extensionToImageIo; + +// src/png-read-image.ts +async function pngReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "png-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var png_read_image_default = pngReadImage; + +// src/png-write-image.ts +async function pngWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "png-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var png_write_image_default = pngWriteImage; + +// src/meta-read-image.ts +async function metaReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "meta-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var meta_read_image_default = metaReadImage; + +// src/meta-write-image.ts +async function metaWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "meta-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var meta_write_image_default = metaWriteImage; + +// src/tiff-read-image.ts +async function tiffReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "tiff-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var tiff_read_image_default = tiffReadImage; + +// src/tiff-write-image.ts +async function tiffWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "tiff-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var tiff_write_image_default = tiffWriteImage; + +// src/nifti-read-image.ts +async function niftiReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "nifti-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var nifti_read_image_default = niftiReadImage; + +// src/nifti-write-image.ts +async function niftiWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "nifti-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var nifti_write_image_default = niftiWriteImage; + +// src/jpeg-read-image.ts +async function jpegReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "jpeg-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var jpeg_read_image_default = jpegReadImage; + +// src/jpeg-write-image.ts +async function jpegWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "jpeg-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var jpeg_write_image_default = jpegWriteImage; + +// src/nrrd-read-image.ts +async function nrrdReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "nrrd-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var nrrd_read_image_default = nrrdReadImage; + +// src/nrrd-write-image.ts +async function nrrdWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "nrrd-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var nrrd_write_image_default = nrrdWriteImage; + +// src/vtk-read-image.ts +async function vtkReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "vtk-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var vtk_read_image_default = vtkReadImage; + +// src/vtk-write-image.ts +async function vtkWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "vtk-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var vtk_write_image_default = vtkWriteImage; + +// src/bmp-read-image.ts +async function bmpReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "bmp-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var bmp_read_image_default = bmpReadImage; + +// src/bmp-write-image.ts +async function bmpWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "bmp-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var bmp_write_image_default = bmpWriteImage; + +// src/hdf5-read-image.ts +async function hdf5ReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "hdf5-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var hdf5_read_image_default = hdf5ReadImage; + +// src/hdf5-write-image.ts +async function hdf5WriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "hdf5-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var hdf5_write_image_default = hdf5WriteImage; + +// src/minc-read-image.ts +async function mincReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "minc-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var minc_read_image_default = mincReadImage; + +// src/minc-write-image.ts +async function mincWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "minc-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var minc_write_image_default = mincWriteImage; + +// src/mrc-read-image.ts +async function mrcReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "mrc-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var mrc_read_image_default = mrcReadImage; + +// src/mrc-write-image.ts +async function mrcWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "mrc-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var mrc_write_image_default = mrcWriteImage; + +// src/lsm-read-image.ts +async function lsmReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "lsm-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var lsm_read_image_default = lsmReadImage; + +// src/lsm-write-image.ts +async function lsmWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "lsm-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var lsm_write_image_default = lsmWriteImage; + +// src/mgh-read-image.ts +async function mghReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "mgh-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var mgh_read_image_default = mghReadImage; + +// src/mgh-write-image.ts +async function mghWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "mgh-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var mgh_write_image_default = mghWriteImage; + +// src/bio-rad-read-image.ts +async function bioRadReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "bio-rad-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var bio_rad_read_image_default = bioRadReadImage; + +// src/bio-rad-write-image.ts +async function bioRadWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "bio-rad-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var bio_rad_write_image_default = bioRadWriteImage; + +// src/gipl-read-image.ts +async function giplReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "gipl-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var gipl_read_image_default = giplReadImage; + +// src/gipl-write-image.ts +async function giplWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "gipl-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var gipl_write_image_default = giplWriteImage; + +// src/ge-adw-read-image.ts +async function geAdwReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "ge-adw-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var ge_adw_read_image_default = geAdwReadImage; + +// src/ge-adw-write-image.ts +async function geAdwWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "ge-adw-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var ge_adw_write_image_default = geAdwWriteImage; + +// src/ge4-read-image.ts +async function ge4ReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "ge4-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var ge4_read_image_default = ge4ReadImage; + +// src/ge4-write-image.ts +async function ge4WriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "ge4-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var ge4_write_image_default = ge4WriteImage; + +// src/ge5-read-image.ts +async function ge5ReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "ge5-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var ge5_read_image_default = ge5ReadImage; + +// src/ge5-write-image.ts +async function ge5WriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "ge5-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var ge5_write_image_default = ge5WriteImage; + +// src/gdcm-read-image.ts +async function gdcmReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "gdcm-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var gdcm_read_image_default = gdcmReadImage; + +// src/gdcm-write-image.ts +async function gdcmWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "gdcm-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var gdcm_write_image_default = gdcmWriteImage; + +// src/scanco-read-image.ts +async function scancoReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "scanco-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var scanco_read_image_default = scancoReadImage; + +// src/scanco-write-image.ts +async function scancoWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "scanco-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var scanco_write_image_default = scancoWriteImage; + +// src/fdf-read-image.ts +async function fdfReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "fdf-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var fdf_read_image_default = fdfReadImage; + +// src/wasm-read-image.ts +async function wasmReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "wasm-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var wasm_read_image_default = wasmReadImage; + +// src/wasm-write-image.ts +async function wasmWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "wasm-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var wasm_write_image_default = wasmWriteImage; + +// src/wasm-zstd-read-image.ts +async function wasmZstdReadImage(webWorker, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.Image } + ]; + let serializedImageFile = serializedImage; + if (serializedImage instanceof File) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + const inputs = [ + { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } + ]; + const args = []; + const serializedImageName = serializedImageFile.path; + args.push(serializedImageName); + const couldReadName = "0"; + args.push(couldReadName); + const imageName = "1"; + args.push(imageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + const pipelinePath = "wasm-zstd-read-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldRead: outputs[0]?.data, + image: outputs[1]?.data + }; + return result; +} +var wasm_zstd_read_image_default = wasmZstdReadImage; + +// src/wasm-zstd-write-image.ts +async function wasmZstdWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "wasm-zstd-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var wasm_zstd_write_image_default = wasmZstdWriteImage; + +// src/image-io-index.ts +var imageIoIndex = /* @__PURE__ */ new Map([ + ["png", [png_read_image_default, png_write_image_default]], + ["meta", [meta_read_image_default, meta_write_image_default]], + ["tiff", [tiff_read_image_default, tiff_write_image_default]], + ["nifti", [nifti_read_image_default, nifti_write_image_default]], + ["jpeg", [jpeg_read_image_default, jpeg_write_image_default]], + ["nrrd", [nrrd_read_image_default, nrrd_write_image_default]], + ["vtk", [vtk_read_image_default, vtk_write_image_default]], + ["bmp", [bmp_read_image_default, bmp_write_image_default]], + ["hdf5", [hdf5_read_image_default, hdf5_write_image_default]], + ["minc", [minc_read_image_default, minc_write_image_default]], + ["mrc", [mrc_read_image_default, mrc_write_image_default]], + ["lsm", [lsm_read_image_default, lsm_write_image_default]], + ["mgh", [mgh_read_image_default, mgh_write_image_default]], + ["bioRad", [bio_rad_read_image_default, bio_rad_write_image_default]], + ["gipl", [gipl_read_image_default, gipl_write_image_default]], + ["geAdw", [ge_adw_read_image_default, ge_adw_write_image_default]], + ["ge4", [ge4_read_image_default, ge4_write_image_default]], + ["ge5", [ge5_read_image_default, ge5_write_image_default]], + ["gdcm", [gdcm_read_image_default, gdcm_write_image_default]], + ["scanco", [scanco_read_image_default, scanco_write_image_default]], + ["fdf", [fdf_read_image_default, null]], + ["wasm", [wasm_read_image_default, wasm_write_image_default]], + ["wasmZstd", [wasm_zstd_read_image_default, wasm_zstd_write_image_default]] +]); +var image_io_index_default = imageIoIndex; + +// src/read-image.ts +async function readImage(webWorker, serializedImage, options = {}) { + const mimeType = serializedImage.type ?? ""; + const fileName = serializedImage.name ?? serializedImage.path ?? "fileName"; + const extension = getFileExtension_default(fileName).toLowerCase(); + let usedWebWorker = webWorker; + let serializedImageFile = serializedImage; + if (serializedImage instanceof Blob) { + const serializedImageBuffer = await serializedImage.arrayBuffer(); + serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; + } + let io = null; + if (mimeType && mime_to_image_io_default.has(mimeType)) { + io = mime_to_image_io_default.get(mimeType); + } else if (extension_to_image_io_default.has(extension)) { + io = extension_to_image_io_default.get(extension); + } else { + for (const readerWriter2 of image_io_index_default.values()) { + if (readerWriter2[0] !== null) { + let { webWorker: testWebWorker2, couldRead: couldRead2, image: image2 } = await readerWriter2[0](usedWebWorker, { path: serializedImageFile.path, data: serializedImageFile.data.slice() }, { informationOnly: options.informationOnly }); + usedWebWorker = testWebWorker2; + if (couldRead2) { + if (typeof options !== "undefined") { + image2 = castImage_default(image2, options); + } + return { webWorker: usedWebWorker, image: image2 }; + } + } + } + } + if (!io) { + throw Error("Could not find IO for: " + fileName); + } + const readerWriter = image_io_index_default.get(io); + const reader = readerWriter[0]; + let { webWorker: testWebWorker, couldRead, image } = await reader(usedWebWorker, serializedImageFile, { informationOnly: options.informationOnly }); + usedWebWorker = testWebWorker; + if (!couldRead) { + throw Error("Could not read: " + fileName); + } + if (typeof options !== "undefined") { + image = castImage_default(image, options); + } + return { webWorker: usedWebWorker, image }; +} +var read_image_default = readImage; + +// src/read-image-file-series.ts +var numberOfWorkers = typeof globalThis.navigator?.hardwareConcurrency === "number" ? globalThis.navigator.hardwareConcurrency : 6; +var workerPool = new WorkerPool_default(numberOfWorkers, read_image_default); +async function readImageFileSeries(fileList, options) { + let zSpacing = 1; + let zOrigin = 0; + let sortedSeries = false; + if (typeof options === "object") { + if (typeof options.zSpacing !== "undefined") { + zSpacing = options.zSpacing; + } + if (typeof options.zOrigin !== "undefined") { + zOrigin = options.zOrigin; + } + if (typeof options.sortedSeries !== "undefined") { + sortedSeries = options.sortedSeries; + } + } + const fetchFileDescriptions = Array.from(fileList, async function(file) { + return await file.arrayBuffer().then(function(arrayBuffer) { + const fileDescription = { + name: file.name, + type: file.type, + data: arrayBuffer + }; + return fileDescription; + }); + }); + const fileDescriptions = await Promise.all(fetchFileDescriptions); + if (!sortedSeries) { + fileDescriptions.sort((a, b) => { + if (a.name < b.name) { + return -1; + } + if (a.name > b.name) { + return 1; + } + return 0; + }); + } + const taskArgsArray = []; + for (let index = 0; index < fileDescriptions.length; index++) { + taskArgsArray.push([fileDescriptions[index].data, fileDescriptions[index].name]); + } + const results = await workerPool.runTasks(taskArgsArray).promise; + const images = results.map((result) => { + const image = result.image; + image.imageType.dimension = 3; + image.size.push(1); + image.spacing.push(zSpacing); + image.origin.push(zOrigin); + image.direction = new Float64Array(9); + image.direction.fill(0); + image.direction[0] = 1; + image.direction[4] = 1; + image.direction[8] = 1; + return image; + }); + let stacked = stackImages_default(images); + if (typeof options === "object" && (typeof options.componentType !== "undefined" || typeof options.pixelType !== "undefined")) { + stacked = castImage_default(stacked, options); + } + return { image: stacked, webWorkerPool: workerPool }; +} +var read_image_file_series_default = readImageFileSeries; + +// src/write-image.ts +async function writeImage(webWorker, image, serializedImage, options = {}) { + let inputImage = image; + if (typeof options.componentType !== "undefined" || typeof options.pixelType !== "undefined") { + inputImage = castImage_default(image, options); + } + const mimeType = options.mimeType; + const extension = getFileExtension_default(serializedImage).toLowerCase(); + let usedWebWorker = webWorker; + let io = null; + if (typeof mimeType !== "undefined" && mime_to_image_io_default.has(mimeType)) { + io = mime_to_image_io_default.get(mimeType); + } else if (extension_to_image_io_default.has(extension)) { + io = extension_to_image_io_default.get(extension); + } else { + for (const readerWriter2 of image_io_index_default.values()) { + if (readerWriter2[1] !== null) { + let { webWorker: testWebWorker2, couldWrite: couldWrite2, serializedImage: serializedImageBuffer2 } = await readerWriter2[1](usedWebWorker, copyImage_default(inputImage), serializedImage, options); + usedWebWorker = testWebWorker2; + if (couldWrite2) { + return { webWorker: usedWebWorker, serializedImage: serializedImageBuffer2 }; + } + } + } + } + if (!io) { + throw Error("Could not find IO for: " + serializedImage); + } + const readerWriter = image_io_index_default.get(io); + const writer = readerWriter[1]; + let { webWorker: testWebWorker, couldWrite, serializedImage: serializedImageBuffer } = await writer(usedWebWorker, inputImage, serializedImage, options); + usedWebWorker = testWebWorker; + if (!couldWrite) { + throw Error("Could not write: " + serializedImage); + } + const result = { + webWorker: usedWebWorker, + serializedImage: serializedImageBuffer + }; + return result; +} +var write_image_default = writeImage; + +// src/fdf-write-image.ts +async function fdfWriteImage(webWorker, image, serializedImage, options = {}) { + const desiredOutputs = [ + { type: InterfaceTypes_default.JsonCompatible }, + { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } + ]; + const inputs = [ + { type: InterfaceTypes_default.Image, data: image } + ]; + const args = []; + const imageName = "0"; + args.push(imageName); + const couldWriteName = "0"; + args.push(couldWriteName); + const serializedImageName = serializedImage; + args.push(serializedImageName); + args.push("--memory-io"); + if (typeof options.informationOnly !== "undefined") { + options.informationOnly && args.push("--information-only"); + } + if (typeof options.useCompression !== "undefined") { + options.useCompression && args.push("--use-compression"); + } + const pipelinePath = "fdf-write-image"; + const { + webWorker: usedWebWorker, + returnValue, + stderr, + outputs + } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); + if (returnValue !== 0 && stderr !== "") { + throw new Error(stderr); + } + const result = { + webWorker: usedWebWorker, + couldWrite: outputs[0]?.data, + serializedImage: outputs[1]?.data + }; + return result; +} +var fdf_write_image_default = fdfWriteImage; + +// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js +var itk_wasm_pipeline_worker_default = 'data:text/javascript;charset=utf-8,var __create = Object.create;%0Avar __defProp = Object.defineProperty;%0Avar __getOwnPropDesc = Object.getOwnPropertyDescriptor;%0Avar __getOwnPropNames = Object.getOwnPropertyNames;%0Avar __getProtoOf = Object.getPrototypeOf;%0Avar __hasOwnProp = Object.prototype.hasOwnProperty;%0Avar __commonJS = (cb, mod) => function __require() {%0A return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;%0A};%0Avar __copyProps = (to, from, except, desc) => {%0A if (from && typeof from === "object" || typeof from === "function") {%0A for (let key of __getOwnPropNames(from))%0A if (!__hasOwnProp.call(to, key) && key !== except)%0A __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });%0A }%0A return to;%0A};%0Avar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(%0A // If the importer is in node compatibility mode or this is not an ESM%0A // file that has been converted to a CommonJS file using a Babel-%0A // compatible transform (i.e. "__esModule" has not been set), then set%0A // "default" to the CommonJS "module.exports" for node compatibility.%0A isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,%0A mod%0A));%0A%0A// node_modules/webworker-promise/lib/tiny-emitter.js%0Avar require_tiny_emitter = __commonJS({%0A "node_modules/webworker-promise/lib/tiny-emitter.js"(exports, module) {%0A "use strict";%0A var _createClass = function() {%0A function defineProperties(target, props) {%0A for (var i = 0; i < props.length; i++) {%0A var descriptor = props[i];%0A descriptor.enumerable = descriptor.enumerable || false;%0A descriptor.configurable = true;%0A if ("value" in descriptor)%0A descriptor.writable = true;%0A Object.defineProperty(target, descriptor.key, descriptor);%0A }%0A }%0A return function(Constructor, protoProps, staticProps) {%0A if (protoProps)%0A defineProperties(Constructor.prototype, protoProps);%0A if (staticProps)%0A defineProperties(Constructor, staticProps);%0A return Constructor;%0A };%0A }();%0A function _classCallCheck(instance2, Constructor) {%0A if (!(instance2 instanceof Constructor)) {%0A throw new TypeError("Cannot call a class as a function");%0A }%0A }%0A var TinyEmitter = function() {%0A function TinyEmitter2() {%0A _classCallCheck(this, TinyEmitter2);%0A Object.defineProperty(this, "__listeners", {%0A value: {},%0A enumerable: false,%0A writable: false%0A });%0A }%0A _createClass(TinyEmitter2, [{%0A key: "emit",%0A value: function emit(eventName) {%0A if (!this.__listeners[eventName])%0A return this;%0A for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {%0A args[_key - 1] = arguments[_key];%0A }%0A var _iteratorNormalCompletion = true;%0A var _didIteratorError = false;%0A var _iteratorError = void 0;%0A try {%0A for (var _iterator = this.__listeners[eventName][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {%0A var handler = _step.value;%0A handler.apply(void 0, args);%0A }%0A } catch (err) {%0A _didIteratorError = true;%0A _iteratorError = err;%0A } finally {%0A try {%0A if (!_iteratorNormalCompletion && _iterator.return) {%0A _iterator.return();%0A }%0A } finally {%0A if (_didIteratorError) {%0A throw _iteratorError;%0A }%0A }%0A }%0A return this;%0A }%0A }, {%0A key: "once",%0A value: function once(eventName, handler) {%0A var _this = this;%0A var once2 = function once3() {%0A _this.off(eventName, once3);%0A handler.apply(void 0, arguments);%0A };%0A return this.on(eventName, once2);%0A }%0A }, {%0A key: "on",%0A value: function on(eventName, handler) {%0A if (!this.__listeners[eventName])%0A this.__listeners[eventName] = [];%0A this.__listeners[eventName].push(handler);%0A return this;%0A }%0A }, {%0A key: "off",%0A value: function off(eventName, handler) {%0A if (handler)%0A this.__listeners[eventName] = this.__listeners[eventName].filter(function(h) {%0A return h !== handler;%0A });%0A else%0A this.__listeners[eventName] = [];%0A return this;%0A }%0A }]);%0A return TinyEmitter2;%0A }();%0A module.exports = TinyEmitter;%0A }%0A});%0A%0A// node_modules/webworker-promise/lib/register.js%0Avar require_register = __commonJS({%0A "node_modules/webworker-promise/lib/register.js"(exports, module) {%0A "use strict";%0A var _createClass = function() {%0A function defineProperties(target, props) {%0A for (var i = 0; i < props.length; i++) {%0A var descriptor = props[i];%0A descriptor.enumerable = descriptor.enumerable || false;%0A descriptor.configurable = true;%0A if ("value" in descriptor)%0A descriptor.writable = true;%0A Object.defineProperty(target, descriptor.key, descriptor);%0A }%0A }%0A return function(Constructor, protoProps, staticProps) {%0A if (protoProps)%0A defineProperties(Constructor.prototype, protoProps);%0A if (staticProps)%0A defineProperties(Constructor, staticProps);%0A return Constructor;%0A };%0A }();%0A var _get = function get(object, property, receiver) {%0A if (object === null)%0A object = Function.prototype;%0A var desc = Object.getOwnPropertyDescriptor(object, property);%0A if (desc === void 0) {%0A var parent = Object.getPrototypeOf(object);%0A if (parent === null) {%0A return void 0;%0A } else {%0A return get(parent, property, receiver);%0A }%0A } else if ("value" in desc) {%0A return desc.value;%0A } else {%0A var getter = desc.get;%0A if (getter === void 0) {%0A return void 0;%0A }%0A return getter.call(receiver);%0A }%0A };%0A var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {%0A return typeof obj;%0A } : function(obj) {%0A return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;%0A };%0A function _toConsumableArray(arr) {%0A if (Array.isArray(arr)) {%0A for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {%0A arr2[i] = arr[i];%0A }%0A return arr2;%0A } else {%0A return Array.from(arr);%0A }%0A }%0A function _classCallCheck(instance2, Constructor) {%0A if (!(instance2 instanceof Constructor)) {%0A throw new TypeError("Cannot call a class as a function");%0A }%0A }%0A function _possibleConstructorReturn(self2, call) {%0A if (!self2) {%0A throw new ReferenceError("this hasn\'t been initialised - super() hasn\'t been called");%0A }%0A return call && (typeof call === "object" || typeof call === "function") ? call : self2;%0A }%0A function _inherits(subClass, superClass) {%0A if (typeof superClass !== "function" && superClass !== null) {%0A throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);%0A }%0A subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });%0A if (superClass)%0A Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;%0A }%0A function _defineProperty(obj, key, value) {%0A if (key in obj) {%0A Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });%0A } else {%0A obj[key] = value;%0A }%0A return obj;%0A }%0A var TinyEmitter = require_tiny_emitter();%0A var MESSAGE_RESULT = 0;%0A var MESSAGE_EVENT = 1;%0A var RESULT_ERROR = 0;%0A var RESULT_SUCCESS = 1;%0A var DEFAULT_HANDLER = "main";%0A var isPromise = function isPromise2(o) {%0A return (typeof o === "undefined" ? "undefined" : _typeof(o)) === "object" && o !== null && typeof o.then === "function" && typeof o.catch === "function";%0A };%0A function RegisterPromise(fn) {%0A var handlers = _defineProperty({}, DEFAULT_HANDLER, fn);%0A var sendPostMessage = self.postMessage.bind(self);%0A var server = new (function(_TinyEmitter) {%0A _inherits(WorkerRegister, _TinyEmitter);%0A function WorkerRegister() {%0A _classCallCheck(this, WorkerRegister);%0A return _possibleConstructorReturn(this, (WorkerRegister.__proto__ || Object.getPrototypeOf(WorkerRegister)).apply(this, arguments));%0A }%0A _createClass(WorkerRegister, [{%0A key: "emit",%0A value: function emit(eventName) {%0A for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {%0A args[_key - 1] = arguments[_key];%0A }%0A if (args.length == 1 && args[0] instanceof TransferableResponse) {%0A sendPostMessage({ eventName, args }, args[0].transferable);%0A } else {%0A sendPostMessage({ eventName, args });%0A }%0A return this;%0A }%0A }, {%0A key: "emitLocally",%0A value: function emitLocally(eventName) {%0A var _get2;%0A for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {%0A args[_key2 - 1] = arguments[_key2];%0A }%0A (_get2 = _get(WorkerRegister.prototype.__proto__ || Object.getPrototypeOf(WorkerRegister.prototype), "emit", this)).call.apply(_get2, [this, eventName].concat(args));%0A }%0A }, {%0A key: "operation",%0A value: function operation(name, handler) {%0A handlers[name] = handler;%0A return this;%0A }%0A }]);%0A return WorkerRegister;%0A }(TinyEmitter))();%0A var run = function run2(messageId, payload, handlerName) {%0A var onSuccess = function onSuccess2(result2) {%0A if (result2 && result2 instanceof TransferableResponse) {%0A sendResult(messageId, RESULT_SUCCESS, result2.payload, result2.transferable);%0A } else {%0A sendResult(messageId, RESULT_SUCCESS, result2);%0A }%0A };%0A var onError = function onError2(e) {%0A sendResult(messageId, RESULT_ERROR, {%0A message: e.message,%0A stack: e.stack%0A });%0A };%0A try {%0A var result = runFn(messageId, payload, handlerName);%0A if (isPromise(result)) {%0A result.then(onSuccess).catch(onError);%0A } else {%0A onSuccess(result);%0A }%0A } catch (e) {%0A onError(e);%0A }%0A };%0A var runFn = function runFn2(messageId, payload, handlerName) {%0A var handler = handlers[handlerName || DEFAULT_HANDLER];%0A if (!handler)%0A throw new Error("Not found handler for this request");%0A return handler(payload, sendEvent.bind(null, messageId));%0A };%0A var sendResult = function sendResult2(messageId, success, payload) {%0A var transferable = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : [];%0A sendPostMessage([MESSAGE_RESULT, messageId, success, payload], transferable);%0A };%0A var sendEvent = function sendEvent2(messageId, eventName, payload) {%0A if (!eventName)%0A throw new Error("eventName is required");%0A if (typeof eventName !== "string")%0A throw new Error("eventName should be string");%0A sendPostMessage([MESSAGE_EVENT, messageId, eventName, payload]);%0A };%0A self.addEventListener("message", function(_ref) {%0A var data = _ref.data;%0A if (Array.isArray(data)) {%0A run.apply(void 0, _toConsumableArray(data));%0A } else if (data && data.eventName) {%0A server.emitLocally.apply(server, [data.eventName].concat(_toConsumableArray(data.args)));%0A }%0A });%0A return server;%0A }%0A var TransferableResponse = function TransferableResponse2(payload, transferable) {%0A _classCallCheck(this, TransferableResponse2);%0A this.payload = payload;%0A this.transferable = transferable;%0A };%0A module.exports = RegisterPromise;%0A module.exports.TransferableResponse = TransferableResponse;%0A }%0A});%0A%0A// dist/core/web-workers/itk-wasm-pipeline.worker.js%0Avar import_register2 = __toESM(require_register(), 1);%0A%0A// node_modules/axios/lib/helpers/bind.js%0Afunction bind(fn, thisArg) {%0A return function wrap() {%0A return fn.apply(thisArg, arguments);%0A };%0A}%0A%0A// node_modules/axios/lib/utils.js%0Avar { toString } = Object.prototype;%0Avar { getPrototypeOf } = Object;%0Avar kindOf = ((cache) => (thing) => {%0A const str = toString.call(thing);%0A return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());%0A})(/* @__PURE__ */ Object.create(null));%0Avar kindOfTest = (type) => {%0A type = type.toLowerCase();%0A return (thing) => kindOf(thing) === type;%0A};%0Avar typeOfTest = (type) => (thing) => typeof thing === type;%0Avar { isArray } = Array;%0Avar isUndefined = typeOfTest("undefined");%0Afunction isBuffer(val) {%0A return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);%0A}%0Avar isArrayBuffer = kindOfTest("ArrayBuffer");%0Afunction isArrayBufferView(val) {%0A let result;%0A if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) {%0A result = ArrayBuffer.isView(val);%0A } else {%0A result = val && val.buffer && isArrayBuffer(val.buffer);%0A }%0A return result;%0A}%0Avar isString = typeOfTest("string");%0Avar isFunction = typeOfTest("function");%0Avar isNumber = typeOfTest("number");%0Avar isObject = (thing) => thing !== null && typeof thing === "object";%0Avar isBoolean = (thing) => thing === true || thing === false;%0Avar isPlainObject = (val) => {%0A if (kindOf(val) !== "object") {%0A return false;%0A }%0A const prototype3 = getPrototypeOf(val);%0A return (prototype3 === null || prototype3 === Object.prototype || Object.getPrototypeOf(prototype3) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val);%0A};%0Avar isDate = kindOfTest("Date");%0Avar isFile = kindOfTest("File");%0Avar isBlob = kindOfTest("Blob");%0Avar isFileList = kindOfTest("FileList");%0Avar isStream = (val) => isObject(val) && isFunction(val.pipe);%0Avar isFormData = (thing) => {%0A let kind;%0A return thing && (typeof FormData === "function" && thing instanceof FormData || isFunction(thing.append) && ((kind = kindOf(thing)) === "formdata" || // detect form-data instance%0A kind === "object" && isFunction(thing.toString) && thing.toString() === "[object FormData]"));%0A};%0Avar isURLSearchParams = kindOfTest("URLSearchParams");%0Avar trim = (str) => str.trim ? str.trim() : str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, "");%0Afunction forEach(obj, fn, { allOwnKeys = false } = {}) {%0A if (obj === null || typeof obj === "undefined") {%0A return;%0A }%0A let i;%0A let l;%0A if (typeof obj !== "object") {%0A obj = [obj];%0A }%0A if (isArray(obj)) {%0A for (i = 0, l = obj.length; i < l; i++) {%0A fn.call(null, obj[i], i, obj);%0A }%0A } else {%0A const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);%0A const len = keys.length;%0A let key;%0A for (i = 0; i < len; i++) {%0A key = keys[i];%0A fn.call(null, obj[key], key, obj);%0A }%0A }%0A}%0Afunction findKey(obj, key) {%0A key = key.toLowerCase();%0A const keys = Object.keys(obj);%0A let i = keys.length;%0A let _key;%0A while (i-- > 0) {%0A _key = keys[i];%0A if (key === _key.toLowerCase()) {%0A return _key;%0A }%0A }%0A return null;%0A}%0Avar _global = (() => {%0A if (typeof globalThis !== "undefined")%0A return globalThis;%0A return typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : global;%0A})();%0Avar isContextDefined = (context) => !isUndefined(context) && context !== _global;%0Afunction merge() {%0A const { caseless } = isContextDefined(this) && this || {};%0A const result = {};%0A const assignValue = (val, key) => {%0A const targetKey = caseless && findKey(result, key) || key;%0A if (isPlainObject(result[targetKey]) && isPlainObject(val)) {%0A result[targetKey] = merge(result[targetKey], val);%0A } else if (isPlainObject(val)) {%0A result[targetKey] = merge({}, val);%0A } else if (isArray(val)) {%0A result[targetKey] = val.slice();%0A } else {%0A result[targetKey] = val;%0A }%0A };%0A for (let i = 0, l = arguments.length; i < l; i++) {%0A arguments[i] && forEach(arguments[i], assignValue);%0A }%0A return result;%0A}%0Avar extend = (a, b, thisArg, { allOwnKeys } = {}) => {%0A forEach(b, (val, key) => {%0A if (thisArg && isFunction(val)) {%0A a[key] = bind(val, thisArg);%0A } else {%0A a[key] = val;%0A }%0A }, { allOwnKeys });%0A return a;%0A};%0Avar stripBOM = (content) => {%0A if (content.charCodeAt(0) === 65279) {%0A content = content.slice(1);%0A }%0A return content;%0A};%0Avar inherits = (constructor, superConstructor, props, descriptors2) => {%0A constructor.prototype = Object.create(superConstructor.prototype, descriptors2);%0A constructor.prototype.constructor = constructor;%0A Object.defineProperty(constructor, "super", {%0A value: superConstructor.prototype%0A });%0A props && Object.assign(constructor.prototype, props);%0A};%0Avar toFlatObject = (sourceObj, destObj, filter2, propFilter) => {%0A let props;%0A let i;%0A let prop;%0A const merged = {};%0A destObj = destObj || {};%0A if (sourceObj == null)%0A return destObj;%0A do {%0A props = Object.getOwnPropertyNames(sourceObj);%0A i = props.length;%0A while (i-- > 0) {%0A prop = props[i];%0A if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {%0A destObj[prop] = sourceObj[prop];%0A merged[prop] = true;%0A }%0A }%0A sourceObj = filter2 !== false && getPrototypeOf(sourceObj);%0A } while (sourceObj && (!filter2 || filter2(sourceObj, destObj)) && sourceObj !== Object.prototype);%0A return destObj;%0A};%0Avar endsWith = (str, searchString, position) => {%0A str = String(str);%0A if (position === void 0 || position > str.length) {%0A position = str.length;%0A }%0A position -= searchString.length;%0A const lastIndex = str.indexOf(searchString, position);%0A return lastIndex !== -1 && lastIndex === position;%0A};%0Avar toArray = (thing) => {%0A if (!thing)%0A return null;%0A if (isArray(thing))%0A return thing;%0A let i = thing.length;%0A if (!isNumber(i))%0A return null;%0A const arr = new Array(i);%0A while (i-- > 0) {%0A arr[i] = thing[i];%0A }%0A return arr;%0A};%0Avar isTypedArray = ((TypedArray) => {%0A return (thing) => {%0A return TypedArray && thing instanceof TypedArray;%0A };%0A})(typeof Uint8Array !== "undefined" && getPrototypeOf(Uint8Array));%0Avar forEachEntry = (obj, fn) => {%0A const generator = obj && obj[Symbol.iterator];%0A const iterator = generator.call(obj);%0A let result;%0A while ((result = iterator.next()) && !result.done) {%0A const pair = result.value;%0A fn.call(obj, pair[0], pair[1]);%0A }%0A};%0Avar matchAll = (regExp, str) => {%0A let matches;%0A const arr = [];%0A while ((matches = regExp.exec(str)) !== null) {%0A arr.push(matches);%0A }%0A return arr;%0A};%0Avar isHTMLForm = kindOfTest("HTMLFormElement");%0Avar toCamelCase = (str) => {%0A return str.toLowerCase().replace(%0A /[-_\\s]([a-z\\d])(\\w*)/g,%0A function replacer(m, p1, p2) {%0A return p1.toUpperCase() + p2;%0A }%0A );%0A};%0Avar hasOwnProperty = (({ hasOwnProperty: hasOwnProperty2 }) => (obj, prop) => hasOwnProperty2.call(obj, prop))(Object.prototype);%0Avar isRegExp = kindOfTest("RegExp");%0Avar reduceDescriptors = (obj, reducer) => {%0A const descriptors2 = Object.getOwnPropertyDescriptors(obj);%0A const reducedDescriptors = {};%0A forEach(descriptors2, (descriptor, name) => {%0A if (reducer(descriptor, name, obj) !== false) {%0A reducedDescriptors[name] = descriptor;%0A }%0A });%0A Object.defineProperties(obj, reducedDescriptors);%0A};%0Avar freezeMethods = (obj) => {%0A reduceDescriptors(obj, (descriptor, name) => {%0A if (isFunction(obj) && ["arguments", "caller", "callee"].indexOf(name) !== -1) {%0A return false;%0A }%0A const value = obj[name];%0A if (!isFunction(value))%0A return;%0A descriptor.enumerable = false;%0A if ("writable" in descriptor) {%0A descriptor.writable = false;%0A return;%0A }%0A if (!descriptor.set) {%0A descriptor.set = () => {%0A throw Error("Can not rewrite read-only method \'" + name + "\'");%0A };%0A }%0A });%0A};%0Avar toObjectSet = (arrayOrString, delimiter) => {%0A const obj = {};%0A const define = (arr) => {%0A arr.forEach((value) => {%0A obj[value] = true;%0A });%0A };%0A isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));%0A return obj;%0A};%0Avar noop = () => {%0A};%0Avar toFiniteNumber = (value, defaultValue) => {%0A value = +value;%0A return Number.isFinite(value) ? value : defaultValue;%0A};%0Avar ALPHA = "abcdefghijklmnopqrstuvwxyz";%0Avar DIGIT = "0123456789";%0Avar ALPHABET = {%0A DIGIT,%0A ALPHA,%0A ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT%0A};%0Avar generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {%0A let str = "";%0A const { length } = alphabet;%0A while (size--) {%0A str += alphabet[Math.random() * length | 0];%0A }%0A return str;%0A};%0Afunction isSpecCompliantForm(thing) {%0A return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === "FormData" && thing[Symbol.iterator]);%0A}%0Avar toJSONObject = (obj) => {%0A const stack = new Array(10);%0A const visit = (source, i) => {%0A if (isObject(source)) {%0A if (stack.indexOf(source) >= 0) {%0A return;%0A }%0A if (!("toJSON" in source)) {%0A stack[i] = source;%0A const target = isArray(source) ? [] : {};%0A forEach(source, (value, key) => {%0A const reducedValue = visit(value, i + 1);%0A !isUndefined(reducedValue) && (target[key] = reducedValue);%0A });%0A stack[i] = void 0;%0A return target;%0A }%0A }%0A return source;%0A };%0A return visit(obj, 0);%0A};%0Avar isAsyncFn = kindOfTest("AsyncFunction");%0Avar isThenable = (thing) => thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch);%0Avar utils_default = {%0A isArray,%0A isArrayBuffer,%0A isBuffer,%0A isFormData,%0A isArrayBufferView,%0A isString,%0A isNumber,%0A isBoolean,%0A isObject,%0A isPlainObject,%0A isUndefined,%0A isDate,%0A isFile,%0A isBlob,%0A isRegExp,%0A isFunction,%0A isStream,%0A isURLSearchParams,%0A isTypedArray,%0A isFileList,%0A forEach,%0A merge,%0A extend,%0A trim,%0A stripBOM,%0A inherits,%0A toFlatObject,%0A kindOf,%0A kindOfTest,%0A endsWith,%0A toArray,%0A forEachEntry,%0A matchAll,%0A isHTMLForm,%0A hasOwnProperty,%0A hasOwnProp: hasOwnProperty,%0A // an alias to avoid ESLint no-prototype-builtins detection%0A reduceDescriptors,%0A freezeMethods,%0A toObjectSet,%0A toCamelCase,%0A noop,%0A toFiniteNumber,%0A findKey,%0A global: _global,%0A isContextDefined,%0A ALPHABET,%0A generateString,%0A isSpecCompliantForm,%0A toJSONObject,%0A isAsyncFn,%0A isThenable%0A};%0A%0A// node_modules/axios/lib/core/AxiosError.js%0Afunction AxiosError(message, code, config, request, response) {%0A Error.call(this);%0A if (Error.captureStackTrace) {%0A Error.captureStackTrace(this, this.constructor);%0A } else {%0A this.stack = new Error().stack;%0A }%0A this.message = message;%0A this.name = "AxiosError";%0A code && (this.code = code);%0A config && (this.config = config);%0A request && (this.request = request);%0A response && (this.response = response);%0A}%0Autils_default.inherits(AxiosError, Error, {%0A toJSON: function toJSON() {%0A return {%0A // Standard%0A message: this.message,%0A name: this.name,%0A // Microsoft%0A description: this.description,%0A number: this.number,%0A // Mozilla%0A fileName: this.fileName,%0A lineNumber: this.lineNumber,%0A columnNumber: this.columnNumber,%0A stack: this.stack,%0A // Axios%0A config: utils_default.toJSONObject(this.config),%0A code: this.code,%0A status: this.response && this.response.status ? this.response.status : null%0A };%0A }%0A});%0Avar prototype = AxiosError.prototype;%0Avar descriptors = {};%0A[%0A "ERR_BAD_OPTION_VALUE",%0A "ERR_BAD_OPTION",%0A "ECONNABORTED",%0A "ETIMEDOUT",%0A "ERR_NETWORK",%0A "ERR_FR_TOO_MANY_REDIRECTS",%0A "ERR_DEPRECATED",%0A "ERR_BAD_RESPONSE",%0A "ERR_BAD_REQUEST",%0A "ERR_CANCELED",%0A "ERR_NOT_SUPPORT",%0A "ERR_INVALID_URL"%0A // eslint-disable-next-line func-names%0A].forEach((code) => {%0A descriptors[code] = { value: code };%0A});%0AObject.defineProperties(AxiosError, descriptors);%0AObject.defineProperty(prototype, "isAxiosError", { value: true });%0AAxiosError.from = (error, code, config, request, response, customProps) => {%0A const axiosError = Object.create(prototype);%0A utils_default.toFlatObject(error, axiosError, function filter2(obj) {%0A return obj !== Error.prototype;%0A }, (prop) => {%0A return prop !== "isAxiosError";%0A });%0A AxiosError.call(axiosError, error.message, code, config, request, response);%0A axiosError.cause = error;%0A axiosError.name = error.name;%0A customProps && Object.assign(axiosError, customProps);%0A return axiosError;%0A};%0Avar AxiosError_default = AxiosError;%0A%0A// node_modules/axios/lib/helpers/null.js%0Avar null_default = null;%0A%0A// node_modules/axios/lib/helpers/toFormData.js%0Afunction isVisitable(thing) {%0A return utils_default.isPlainObject(thing) || utils_default.isArray(thing);%0A}%0Afunction removeBrackets(key) {%0A return utils_default.endsWith(key, "[]") ? key.slice(0, -2) : key;%0A}%0Afunction renderKey(path, key, dots) {%0A if (!path)%0A return key;%0A return path.concat(key).map(function each(token, i) {%0A token = removeBrackets(token);%0A return !dots && i ? "[" + token + "]" : token;%0A }).join(dots ? "." : "");%0A}%0Afunction isFlatArray(arr) {%0A return utils_default.isArray(arr) && !arr.some(isVisitable);%0A}%0Avar predicates = utils_default.toFlatObject(utils_default, {}, null, function filter(prop) {%0A return /^is[A-Z]/.test(prop);%0A});%0Afunction toFormData(obj, formData, options) {%0A if (!utils_default.isObject(obj)) {%0A throw new TypeError("target must be an object");%0A }%0A formData = formData || new (null_default || FormData)();%0A options = utils_default.toFlatObject(options, {%0A metaTokens: true,%0A dots: false,%0A indexes: false%0A }, false, function defined(option, source) {%0A return !utils_default.isUndefined(source[option]);%0A });%0A const metaTokens = options.metaTokens;%0A const visitor = options.visitor || defaultVisitor;%0A const dots = options.dots;%0A const indexes = options.indexes;%0A const _Blob = options.Blob || typeof Blob !== "undefined" && Blob;%0A const useBlob = _Blob && utils_default.isSpecCompliantForm(formData);%0A if (!utils_default.isFunction(visitor)) {%0A throw new TypeError("visitor must be a function");%0A }%0A function convertValue(value) {%0A if (value === null)%0A return "";%0A if (utils_default.isDate(value)) {%0A return value.toISOString();%0A }%0A if (!useBlob && utils_default.isBlob(value)) {%0A throw new AxiosError_default("Blob is not supported. Use a Buffer instead.");%0A }%0A if (utils_default.isArrayBuffer(value) || utils_default.isTypedArray(value)) {%0A return useBlob && typeof Blob === "function" ? new Blob([value]) : Buffer.from(value);%0A }%0A return value;%0A }%0A function defaultVisitor(value, key, path) {%0A let arr = value;%0A if (value && !path && typeof value === "object") {%0A if (utils_default.endsWith(key, "{}")) {%0A key = metaTokens ? key : key.slice(0, -2);%0A value = JSON.stringify(value);%0A } else if (utils_default.isArray(value) && isFlatArray(value) || (utils_default.isFileList(value) || utils_default.endsWith(key, "[]")) && (arr = utils_default.toArray(value))) {%0A key = removeBrackets(key);%0A arr.forEach(function each(el, index) {%0A !(utils_default.isUndefined(el) || el === null) && formData.append(%0A // eslint-disable-next-line no-nested-ternary%0A indexes === true ? renderKey([key], index, dots) : indexes === null ? key : key + "[]",%0A convertValue(el)%0A );%0A });%0A return false;%0A }%0A }%0A if (isVisitable(value)) {%0A return true;%0A }%0A formData.append(renderKey(path, key, dots), convertValue(value));%0A return false;%0A }%0A const stack = [];%0A const exposedHelpers = Object.assign(predicates, {%0A defaultVisitor,%0A convertValue,%0A isVisitable%0A });%0A function build(value, path) {%0A if (utils_default.isUndefined(value))%0A return;%0A if (stack.indexOf(value) !== -1) {%0A throw Error("Circular reference detected in " + path.join("."));%0A }%0A stack.push(value);%0A utils_default.forEach(value, function each(el, key) {%0A const result = !(utils_default.isUndefined(el) || el === null) && visitor.call(%0A formData,%0A el,%0A utils_default.isString(key) ? key.trim() : key,%0A path,%0A exposedHelpers%0A );%0A if (result === true) {%0A build(el, path ? path.concat(key) : [key]);%0A }%0A });%0A stack.pop();%0A }%0A if (!utils_default.isObject(obj)) {%0A throw new TypeError("data must be an object");%0A }%0A build(obj);%0A return formData;%0A}%0Avar toFormData_default = toFormData;%0A%0A// node_modules/axios/lib/helpers/AxiosURLSearchParams.js%0Afunction encode(str) {%0A const charMap = {%0A "!": "%2521",%0A "\'": "%2527",%0A "(": "%2528",%0A ")": "%2529",%0A "~": "%257E",%0A "%2520": "+",%0A "%2500": "\\0"%0A };%0A return encodeURIComponent(str).replace(/[!\'()~]|%2520|%2500/g, function replacer(match) {%0A return charMap[match];%0A });%0A}%0Afunction AxiosURLSearchParams(params, options) {%0A this._pairs = [];%0A params && toFormData_default(params, this, options);%0A}%0Avar prototype2 = AxiosURLSearchParams.prototype;%0Aprototype2.append = function append(name, value) {%0A this._pairs.push([name, value]);%0A};%0Aprototype2.toString = function toString2(encoder2) {%0A const _encode = encoder2 ? function(value) {%0A return encoder2.call(this, value, encode);%0A } : encode;%0A return this._pairs.map(function each(pair) {%0A return _encode(pair[0]) + "=" + _encode(pair[1]);%0A }, "").join("&");%0A};%0Avar AxiosURLSearchParams_default = AxiosURLSearchParams;%0A%0A// node_modules/axios/lib/helpers/buildURL.js%0Afunction encode2(val) {%0A return encodeURIComponent(val).replace(/%253A/gi, ":").replace(/%2524/g, "$").replace(/%252C/gi, ",").replace(/%2520/g, "+").replace(/%255B/gi, "[").replace(/%255D/gi, "]");%0A}%0Afunction buildURL(url, params, options) {%0A if (!params) {%0A return url;%0A }%0A const _encode = options && options.encode || encode2;%0A const serializeFn = options && options.serialize;%0A let serializedParams;%0A if (serializeFn) {%0A serializedParams = serializeFn(params, options);%0A } else {%0A serializedParams = utils_default.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams_default(params, options).toString(_encode);%0A }%0A if (serializedParams) {%0A const hashmarkIndex = url.indexOf("%23");%0A if (hashmarkIndex !== -1) {%0A url = url.slice(0, hashmarkIndex);%0A }%0A url += (url.indexOf("?") === -1 ? "?" : "&") + serializedParams;%0A }%0A return url;%0A}%0A%0A// node_modules/axios/lib/core/InterceptorManager.js%0Avar InterceptorManager = class {%0A constructor() {%0A this.handlers = [];%0A }%0A /**%0A * Add a new interceptor to the stack%0A *%0A * @param {Function} fulfilled The function to handle `then` for a `Promise`%0A * @param {Function} rejected The function to handle `reject` for a `Promise`%0A *%0A * @return {Number} An ID used to remove interceptor later%0A */%0A use(fulfilled, rejected, options) {%0A this.handlers.push({%0A fulfilled,%0A rejected,%0A synchronous: options ? options.synchronous : false,%0A runWhen: options ? options.runWhen : null%0A });%0A return this.handlers.length - 1;%0A }%0A /**%0A * Remove an interceptor from the stack%0A *%0A * @param {Number} id The ID that was returned by `use`%0A *%0A * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise%0A */%0A eject(id) {%0A if (this.handlers[id]) {%0A this.handlers[id] = null;%0A }%0A }%0A /**%0A * Clear all interceptors from the stack%0A *%0A * @returns {void}%0A */%0A clear() {%0A if (this.handlers) {%0A this.handlers = [];%0A }%0A }%0A /**%0A * Iterate over all the registered interceptors%0A *%0A * This method is particularly useful for skipping over any%0A * interceptors that may have become `null` calling `eject`.%0A *%0A * @param {Function} fn The function to call for each interceptor%0A *%0A * @returns {void}%0A */%0A forEach(fn) {%0A utils_default.forEach(this.handlers, function forEachHandler(h) {%0A if (h !== null) {%0A fn(h);%0A }%0A });%0A }%0A};%0Avar InterceptorManager_default = InterceptorManager;%0A%0A// node_modules/axios/lib/defaults/transitional.js%0Avar transitional_default = {%0A silentJSONParsing: true,%0A forcedJSONParsing: true,%0A clarifyTimeoutError: false%0A};%0A%0A// node_modules/axios/lib/platform/browser/classes/URLSearchParams.js%0Avar URLSearchParams_default = typeof URLSearchParams !== "undefined" ? URLSearchParams : AxiosURLSearchParams_default;%0A%0A// node_modules/axios/lib/platform/browser/classes/FormData.js%0Avar FormData_default = typeof FormData !== "undefined" ? FormData : null;%0A%0A// node_modules/axios/lib/platform/browser/classes/Blob.js%0Avar Blob_default = typeof Blob !== "undefined" ? Blob : null;%0A%0A// node_modules/axios/lib/platform/browser/index.js%0Avar isStandardBrowserEnv = (() => {%0A let product;%0A if (typeof navigator !== "undefined" && ((product = navigator.product) === "ReactNative" || product === "NativeScript" || product === "NS")) {%0A return false;%0A }%0A return typeof window !== "undefined" && typeof document !== "undefined";%0A})();%0Avar isStandardBrowserWebWorkerEnv = (() => {%0A return typeof WorkerGlobalScope !== "undefined" && // eslint-disable-next-line no-undef%0A self instanceof WorkerGlobalScope && typeof self.importScripts === "function";%0A})();%0Avar browser_default = {%0A isBrowser: true,%0A classes: {%0A URLSearchParams: URLSearchParams_default,%0A FormData: FormData_default,%0A Blob: Blob_default%0A },%0A isStandardBrowserEnv,%0A isStandardBrowserWebWorkerEnv,%0A protocols: ["http", "https", "file", "blob", "url", "data"]%0A};%0A%0A// node_modules/axios/lib/helpers/toURLEncodedForm.js%0Afunction toURLEncodedForm(data, options) {%0A return toFormData_default(data, new browser_default.classes.URLSearchParams(), Object.assign({%0A visitor: function(value, key, path, helpers) {%0A if (browser_default.isNode && utils_default.isBuffer(value)) {%0A this.append(key, value.toString("base64"));%0A return false;%0A }%0A return helpers.defaultVisitor.apply(this, arguments);%0A }%0A }, options));%0A}%0A%0A// node_modules/axios/lib/helpers/formDataToJSON.js%0Afunction parsePropPath(name) {%0A return utils_default.matchAll(/\\w+|\\[(\\w*)]/g, name).map((match) => {%0A return match[0] === "[]" ? "" : match[1] || match[0];%0A });%0A}%0Afunction arrayToObject(arr) {%0A const obj = {};%0A const keys = Object.keys(arr);%0A let i;%0A const len = keys.length;%0A let key;%0A for (i = 0; i < len; i++) {%0A key = keys[i];%0A obj[key] = arr[key];%0A }%0A return obj;%0A}%0Afunction formDataToJSON(formData) {%0A function buildPath(path, value, target, index) {%0A let name = path[index++];%0A const isNumericKey = Number.isFinite(+name);%0A const isLast = index >= path.length;%0A name = !name && utils_default.isArray(target) ? target.length : name;%0A if (isLast) {%0A if (utils_default.hasOwnProp(target, name)) {%0A target[name] = [target[name], value];%0A } else {%0A target[name] = value;%0A }%0A return !isNumericKey;%0A }%0A if (!target[name] || !utils_default.isObject(target[name])) {%0A target[name] = [];%0A }%0A const result = buildPath(path, value, target[name], index);%0A if (result && utils_default.isArray(target[name])) {%0A target[name] = arrayToObject(target[name]);%0A }%0A return !isNumericKey;%0A }%0A if (utils_default.isFormData(formData) && utils_default.isFunction(formData.entries)) {%0A const obj = {};%0A utils_default.forEachEntry(formData, (name, value) => {%0A buildPath(parsePropPath(name), value, obj, 0);%0A });%0A return obj;%0A }%0A return null;%0A}%0Avar formDataToJSON_default = formDataToJSON;%0A%0A// node_modules/axios/lib/defaults/index.js%0Avar DEFAULT_CONTENT_TYPE = {%0A "Content-Type": void 0%0A};%0Afunction stringifySafely(rawValue, parser, encoder2) {%0A if (utils_default.isString(rawValue)) {%0A try {%0A (parser || JSON.parse)(rawValue);%0A return utils_default.trim(rawValue);%0A } catch (e) {%0A if (e.name !== "SyntaxError") {%0A throw e;%0A }%0A }%0A }%0A return (encoder2 || JSON.stringify)(rawValue);%0A}%0Avar defaults = {%0A transitional: transitional_default,%0A adapter: ["xhr", "http"],%0A transformRequest: [function transformRequest(data, headers) {%0A const contentType = headers.getContentType() || "";%0A const hasJSONContentType = contentType.indexOf("application/json") > -1;%0A const isObjectPayload = utils_default.isObject(data);%0A if (isObjectPayload && utils_default.isHTMLForm(data)) {%0A data = new FormData(data);%0A }%0A const isFormData2 = utils_default.isFormData(data);%0A if (isFormData2) {%0A if (!hasJSONContentType) {%0A return data;%0A }%0A return hasJSONContentType ? JSON.stringify(formDataToJSON_default(data)) : data;%0A }%0A if (utils_default.isArrayBuffer(data) || utils_default.isBuffer(data) || utils_default.isStream(data) || utils_default.isFile(data) || utils_default.isBlob(data)) {%0A return data;%0A }%0A if (utils_default.isArrayBufferView(data)) {%0A return data.buffer;%0A }%0A if (utils_default.isURLSearchParams(data)) {%0A headers.setContentType("application/x-www-form-urlencoded;charset=utf-8", false);%0A return data.toString();%0A }%0A let isFileList2;%0A if (isObjectPayload) {%0A if (contentType.indexOf("application/x-www-form-urlencoded") > -1) {%0A return toURLEncodedForm(data, this.formSerializer).toString();%0A }%0A if ((isFileList2 = utils_default.isFileList(data)) || contentType.indexOf("multipart/form-data") > -1) {%0A const _FormData = this.env && this.env.FormData;%0A return toFormData_default(%0A isFileList2 ? { "files[]": data } : data,%0A _FormData && new _FormData(),%0A this.formSerializer%0A );%0A }%0A }%0A if (isObjectPayload || hasJSONContentType) {%0A headers.setContentType("application/json", false);%0A return stringifySafely(data);%0A }%0A return data;%0A }],%0A transformResponse: [function transformResponse(data) {%0A const transitional2 = this.transitional || defaults.transitional;%0A const forcedJSONParsing = transitional2 && transitional2.forcedJSONParsing;%0A const JSONRequested = this.responseType === "json";%0A if (data && utils_default.isString(data) && (forcedJSONParsing && !this.responseType || JSONRequested)) {%0A const silentJSONParsing = transitional2 && transitional2.silentJSONParsing;%0A const strictJSONParsing = !silentJSONParsing && JSONRequested;%0A try {%0A return JSON.parse(data);%0A } catch (e) {%0A if (strictJSONParsing) {%0A if (e.name === "SyntaxError") {%0A throw AxiosError_default.from(e, AxiosError_default.ERR_BAD_RESPONSE, this, null, this.response);%0A }%0A throw e;%0A }%0A }%0A }%0A return data;%0A }],%0A /**%0A * A timeout in milliseconds to abort a request. If set to 0 (default) a%0A * timeout is not created.%0A */%0A timeout: 0,%0A xsrfCookieName: "XSRF-TOKEN",%0A xsrfHeaderName: "X-XSRF-TOKEN",%0A maxContentLength: -1,%0A maxBodyLength: -1,%0A env: {%0A FormData: browser_default.classes.FormData,%0A Blob: browser_default.classes.Blob%0A },%0A validateStatus: function validateStatus(status) {%0A return status >= 200 && status < 300;%0A },%0A headers: {%0A common: {%0A "Accept": "application/json, text/plain, */*"%0A }%0A }%0A};%0Autils_default.forEach(["delete", "get", "head"], function forEachMethodNoData(method) {%0A defaults.headers[method] = {};%0A});%0Autils_default.forEach(["post", "put", "patch"], function forEachMethodWithData(method) {%0A defaults.headers[method] = utils_default.merge(DEFAULT_CONTENT_TYPE);%0A});%0Avar defaults_default = defaults;%0A%0A// node_modules/axios/lib/helpers/parseHeaders.js%0Avar ignoreDuplicateOf = utils_default.toObjectSet([%0A "age",%0A "authorization",%0A "content-length",%0A "content-type",%0A "etag",%0A "expires",%0A "from",%0A "host",%0A "if-modified-since",%0A "if-unmodified-since",%0A "last-modified",%0A "location",%0A "max-forwards",%0A "proxy-authorization",%0A "referer",%0A "retry-after",%0A "user-agent"%0A]);%0Avar parseHeaders_default = (rawHeaders) => {%0A const parsed = {};%0A let key;%0A let val;%0A let i;%0A rawHeaders && rawHeaders.split("\\n").forEach(function parser(line) {%0A i = line.indexOf(":");%0A key = line.substring(0, i).trim().toLowerCase();%0A val = line.substring(i + 1).trim();%0A if (!key || parsed[key] && ignoreDuplicateOf[key]) {%0A return;%0A }%0A if (key === "set-cookie") {%0A if (parsed[key]) {%0A parsed[key].push(val);%0A } else {%0A parsed[key] = [val];%0A }%0A } else {%0A parsed[key] = parsed[key] ? parsed[key] + ", " + val : val;%0A }%0A });%0A return parsed;%0A};%0A%0A// node_modules/axios/lib/core/AxiosHeaders.js%0Avar $internals = Symbol("internals");%0Afunction normalizeHeader(header) {%0A return header && String(header).trim().toLowerCase();%0A}%0Afunction normalizeValue(value) {%0A if (value === false || value == null) {%0A return value;%0A }%0A return utils_default.isArray(value) ? value.map(normalizeValue) : String(value);%0A}%0Afunction parseTokens(str) {%0A const tokens = /* @__PURE__ */ Object.create(null);%0A const tokensRE = /([^\\s,;=]+)\\s*(?:=\\s*([^,;]+))?/g;%0A let match;%0A while (match = tokensRE.exec(str)) {%0A tokens[match[1]] = match[2];%0A }%0A return tokens;%0A}%0Avar isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!%23$%&\'*+.]+$/.test(str.trim());%0Afunction matchHeaderValue(context, value, header, filter2, isHeaderNameFilter) {%0A if (utils_default.isFunction(filter2)) {%0A return filter2.call(this, value, header);%0A }%0A if (isHeaderNameFilter) {%0A value = header;%0A }%0A if (!utils_default.isString(value))%0A return;%0A if (utils_default.isString(filter2)) {%0A return value.indexOf(filter2) !== -1;%0A }%0A if (utils_default.isRegExp(filter2)) {%0A return filter2.test(value);%0A }%0A}%0Afunction formatHeader(header) {%0A return header.trim().toLowerCase().replace(/([a-z\\d])(\\w*)/g, (w, char, str) => {%0A return char.toUpperCase() + str;%0A });%0A}%0Afunction buildAccessors(obj, header) {%0A const accessorName = utils_default.toCamelCase(" " + header);%0A ["get", "set", "has"].forEach((methodName) => {%0A Object.defineProperty(obj, methodName + accessorName, {%0A value: function(arg1, arg2, arg3) {%0A return this[methodName].call(this, header, arg1, arg2, arg3);%0A },%0A configurable: true%0A });%0A });%0A}%0Avar AxiosHeaders = class {%0A constructor(headers) {%0A headers && this.set(headers);%0A }%0A set(header, valueOrRewrite, rewrite) {%0A const self2 = this;%0A function setHeader(_value, _header, _rewrite) {%0A const lHeader = normalizeHeader(_header);%0A if (!lHeader) {%0A throw new Error("header name must be a non-empty string");%0A }%0A const key = utils_default.findKey(self2, lHeader);%0A if (!key || self2[key] === void 0 || _rewrite === true || _rewrite === void 0 && self2[key] !== false) {%0A self2[key || _header] = normalizeValue(_value);%0A }%0A }%0A const setHeaders = (headers, _rewrite) => utils_default.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite));%0A if (utils_default.isPlainObject(header) || header instanceof this.constructor) {%0A setHeaders(header, valueOrRewrite);%0A } else if (utils_default.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) {%0A setHeaders(parseHeaders_default(header), valueOrRewrite);%0A } else {%0A header != null && setHeader(valueOrRewrite, header, rewrite);%0A }%0A return this;%0A }%0A get(header, parser) {%0A header = normalizeHeader(header);%0A if (header) {%0A const key = utils_default.findKey(this, header);%0A if (key) {%0A const value = this[key];%0A if (!parser) {%0A return value;%0A }%0A if (parser === true) {%0A return parseTokens(value);%0A }%0A if (utils_default.isFunction(parser)) {%0A return parser.call(this, value, key);%0A }%0A if (utils_default.isRegExp(parser)) {%0A return parser.exec(value);%0A }%0A throw new TypeError("parser must be boolean|regexp|function");%0A }%0A }%0A }%0A has(header, matcher) {%0A header = normalizeHeader(header);%0A if (header) {%0A const key = utils_default.findKey(this, header);%0A return !!(key && this[key] !== void 0 && (!matcher || matchHeaderValue(this, this[key], key, matcher)));%0A }%0A return false;%0A }%0A delete(header, matcher) {%0A const self2 = this;%0A let deleted = false;%0A function deleteHeader(_header) {%0A _header = normalizeHeader(_header);%0A if (_header) {%0A const key = utils_default.findKey(self2, _header);%0A if (key && (!matcher || matchHeaderValue(self2, self2[key], key, matcher))) {%0A delete self2[key];%0A deleted = true;%0A }%0A }%0A }%0A if (utils_default.isArray(header)) {%0A header.forEach(deleteHeader);%0A } else {%0A deleteHeader(header);%0A }%0A return deleted;%0A }%0A clear(matcher) {%0A const keys = Object.keys(this);%0A let i = keys.length;%0A let deleted = false;%0A while (i--) {%0A const key = keys[i];%0A if (!matcher || matchHeaderValue(this, this[key], key, matcher, true)) {%0A delete this[key];%0A deleted = true;%0A }%0A }%0A return deleted;%0A }%0A normalize(format) {%0A const self2 = this;%0A const headers = {};%0A utils_default.forEach(this, (value, header) => {%0A const key = utils_default.findKey(headers, header);%0A if (key) {%0A self2[key] = normalizeValue(value);%0A delete self2[header];%0A return;%0A }%0A const normalized = format ? formatHeader(header) : String(header).trim();%0A if (normalized !== header) {%0A delete self2[header];%0A }%0A self2[normalized] = normalizeValue(value);%0A headers[normalized] = true;%0A });%0A return this;%0A }%0A concat(...targets) {%0A return this.constructor.concat(this, ...targets);%0A }%0A toJSON(asStrings) {%0A const obj = /* @__PURE__ */ Object.create(null);%0A utils_default.forEach(this, (value, header) => {%0A value != null && value !== false && (obj[header] = asStrings && utils_default.isArray(value) ? value.join(", ") : value);%0A });%0A return obj;%0A }%0A [Symbol.iterator]() {%0A return Object.entries(this.toJSON())[Symbol.iterator]();%0A }%0A toString() {%0A return Object.entries(this.toJSON()).map(([header, value]) => header + ": " + value).join("\\n");%0A }%0A get [Symbol.toStringTag]() {%0A return "AxiosHeaders";%0A }%0A static from(thing) {%0A return thing instanceof this ? thing : new this(thing);%0A }%0A static concat(first, ...targets) {%0A const computed = new this(first);%0A targets.forEach((target) => computed.set(target));%0A return computed;%0A }%0A static accessor(header) {%0A const internals = this[$internals] = this[$internals] = {%0A accessors: {}%0A };%0A const accessors = internals.accessors;%0A const prototype3 = this.prototype;%0A function defineAccessor(_header) {%0A const lHeader = normalizeHeader(_header);%0A if (!accessors[lHeader]) {%0A buildAccessors(prototype3, _header);%0A accessors[lHeader] = true;%0A }%0A }%0A utils_default.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header);%0A return this;%0A }%0A};%0AAxiosHeaders.accessor(["Content-Type", "Content-Length", "Accept", "Accept-Encoding", "User-Agent", "Authorization"]);%0Autils_default.freezeMethods(AxiosHeaders.prototype);%0Autils_default.freezeMethods(AxiosHeaders);%0Avar AxiosHeaders_default = AxiosHeaders;%0A%0A// node_modules/axios/lib/core/transformData.js%0Afunction transformData(fns, response) {%0A const config = this || defaults_default;%0A const context = response || config;%0A const headers = AxiosHeaders_default.from(context.headers);%0A let data = context.data;%0A utils_default.forEach(fns, function transform(fn) {%0A data = fn.call(config, data, headers.normalize(), response ? response.status : void 0);%0A });%0A headers.normalize();%0A return data;%0A}%0A%0A// node_modules/axios/lib/cancel/isCancel.js%0Afunction isCancel(value) {%0A return !!(value && value.__CANCEL__);%0A}%0A%0A// node_modules/axios/lib/cancel/CanceledError.js%0Afunction CanceledError(message, config, request) {%0A AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);%0A this.name = "CanceledError";%0A}%0Autils_default.inherits(CanceledError, AxiosError_default, {%0A __CANCEL__: true%0A});%0Avar CanceledError_default = CanceledError;%0A%0A// node_modules/axios/lib/core/settle.js%0Afunction settle(resolve, reject, response) {%0A const validateStatus2 = response.config.validateStatus;%0A if (!response.status || !validateStatus2 || validateStatus2(response.status)) {%0A resolve(response);%0A } else {%0A reject(new AxiosError_default(%0A "Request failed with status code " + response.status,%0A [AxiosError_default.ERR_BAD_REQUEST, AxiosError_default.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],%0A response.config,%0A response.request,%0A response%0A ));%0A }%0A}%0A%0A// node_modules/axios/lib/helpers/cookies.js%0Avar cookies_default = browser_default.isStandardBrowserEnv ? (%0A // Standard browser envs support document.cookie%0A function standardBrowserEnv() {%0A return {%0A write: function write(name, value, expires, path, domain, secure) {%0A const cookie = [];%0A cookie.push(name + "=" + encodeURIComponent(value));%0A if (utils_default.isNumber(expires)) {%0A cookie.push("expires=" + new Date(expires).toGMTString());%0A }%0A if (utils_default.isString(path)) {%0A cookie.push("path=" + path);%0A }%0A if (utils_default.isString(domain)) {%0A cookie.push("domain=" + domain);%0A }%0A if (secure === true) {%0A cookie.push("secure");%0A }%0A document.cookie = cookie.join("; ");%0A },%0A read: function read(name) {%0A const match = document.cookie.match(new RegExp("(^|;\\\\s*)(" + name + ")=([^;]*)"));%0A return match ? decodeURIComponent(match[3]) : null;%0A },%0A remove: function remove(name) {%0A this.write(name, "", Date.now() - 864e5);%0A }%0A };%0A }()%0A) : (%0A // Non standard browser env (web workers, react-native) lack needed support.%0A function nonStandardBrowserEnv() {%0A return {%0A write: function write() {%0A },%0A read: function read() {%0A return null;%0A },%0A remove: function remove() {%0A }%0A };%0A }()%0A);%0A%0A// node_modules/axios/lib/helpers/isAbsoluteURL.js%0Afunction isAbsoluteURL(url) {%0A return /^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(url);%0A}%0A%0A// node_modules/axios/lib/helpers/combineURLs.js%0Afunction combineURLs(baseURL, relativeURL) {%0A return relativeURL ? baseURL.replace(/\\/+$/, "") + "/" + relativeURL.replace(/^\\/+/, "") : baseURL;%0A}%0A%0A// node_modules/axios/lib/core/buildFullPath.js%0Afunction buildFullPath(baseURL, requestedURL) {%0A if (baseURL && !isAbsoluteURL(requestedURL)) {%0A return combineURLs(baseURL, requestedURL);%0A }%0A return requestedURL;%0A}%0A%0A// node_modules/axios/lib/helpers/isURLSameOrigin.js%0Avar isURLSameOrigin_default = browser_default.isStandardBrowserEnv ? (%0A // Standard browser envs have full support of the APIs needed to test%0A // whether the request URL is of the same origin as current location.%0A function standardBrowserEnv2() {%0A const msie = /(msie|trident)/i.test(navigator.userAgent);%0A const urlParsingNode = document.createElement("a");%0A let originURL;%0A function resolveURL(url) {%0A let href = url;%0A if (msie) {%0A urlParsingNode.setAttribute("href", href);%0A href = urlParsingNode.href;%0A }%0A urlParsingNode.setAttribute("href", href);%0A return {%0A href: urlParsingNode.href,%0A protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, "") : "",%0A host: urlParsingNode.host,%0A search: urlParsingNode.search ? urlParsingNode.search.replace(/^\\?/, "") : "",%0A hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^%23/, "") : "",%0A hostname: urlParsingNode.hostname,%0A port: urlParsingNode.port,%0A pathname: urlParsingNode.pathname.charAt(0) === "/" ? urlParsingNode.pathname : "/" + urlParsingNode.pathname%0A };%0A }%0A originURL = resolveURL(window.location.href);%0A return function isURLSameOrigin(requestURL) {%0A const parsed = utils_default.isString(requestURL) ? resolveURL(requestURL) : requestURL;%0A return parsed.protocol === originURL.protocol && parsed.host === originURL.host;%0A };%0A }()%0A) : (%0A // Non standard browser envs (web workers, react-native) lack needed support.%0A function nonStandardBrowserEnv2() {%0A return function isURLSameOrigin() {%0A return true;%0A };%0A }()%0A);%0A%0A// node_modules/axios/lib/helpers/parseProtocol.js%0Afunction parseProtocol(url) {%0A const match = /^([-+\\w]{1,25})(:?\\/\\/|:)/.exec(url);%0A return match && match[1] || "";%0A}%0A%0A// node_modules/axios/lib/helpers/speedometer.js%0Afunction speedometer(samplesCount, min) {%0A samplesCount = samplesCount || 10;%0A const bytes = new Array(samplesCount);%0A const timestamps = new Array(samplesCount);%0A let head = 0;%0A let tail = 0;%0A let firstSampleTS;%0A min = min !== void 0 ? min : 1e3;%0A return function push(chunkLength) {%0A const now = Date.now();%0A const startedAt = timestamps[tail];%0A if (!firstSampleTS) {%0A firstSampleTS = now;%0A }%0A bytes[head] = chunkLength;%0A timestamps[head] = now;%0A let i = tail;%0A let bytesCount = 0;%0A while (i !== head) {%0A bytesCount += bytes[i++];%0A i = i % samplesCount;%0A }%0A head = (head + 1) % samplesCount;%0A if (head === tail) {%0A tail = (tail + 1) % samplesCount;%0A }%0A if (now - firstSampleTS < min) {%0A return;%0A }%0A const passed = startedAt && now - startedAt;%0A return passed ? Math.round(bytesCount * 1e3 / passed) : void 0;%0A };%0A}%0Avar speedometer_default = speedometer;%0A%0A// node_modules/axios/lib/adapters/xhr.js%0Afunction progressEventReducer(listener, isDownloadStream) {%0A let bytesNotified = 0;%0A const _speedometer = speedometer_default(50, 250);%0A return (e) => {%0A const loaded = e.loaded;%0A const total = e.lengthComputable ? e.total : void 0;%0A const progressBytes = loaded - bytesNotified;%0A const rate = _speedometer(progressBytes);%0A const inRange = loaded <= total;%0A bytesNotified = loaded;%0A const data = {%0A loaded,%0A total,%0A progress: total ? loaded / total : void 0,%0A bytes: progressBytes,%0A rate: rate ? rate : void 0,%0A estimated: rate && total && inRange ? (total - loaded) / rate : void 0,%0A event: e%0A };%0A data[isDownloadStream ? "download" : "upload"] = true;%0A listener(data);%0A };%0A}%0Avar isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined";%0Avar xhr_default = isXHRAdapterSupported && function(config) {%0A return new Promise(function dispatchXhrRequest(resolve, reject) {%0A let requestData = config.data;%0A const requestHeaders = AxiosHeaders_default.from(config.headers).normalize();%0A const responseType = config.responseType;%0A let onCanceled;%0A function done() {%0A if (config.cancelToken) {%0A config.cancelToken.unsubscribe(onCanceled);%0A }%0A if (config.signal) {%0A config.signal.removeEventListener("abort", onCanceled);%0A }%0A }%0A if (utils_default.isFormData(requestData)) {%0A if (browser_default.isStandardBrowserEnv || browser_default.isStandardBrowserWebWorkerEnv) {%0A requestHeaders.setContentType(false);%0A } else {%0A requestHeaders.setContentType("multipart/form-data;", false);%0A }%0A }%0A let request = new XMLHttpRequest();%0A if (config.auth) {%0A const username = config.auth.username || "";%0A const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : "";%0A requestHeaders.set("Authorization", "Basic " + btoa(username + ":" + password));%0A }%0A const fullPath = buildFullPath(config.baseURL, config.url);%0A request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);%0A request.timeout = config.timeout;%0A function onloadend() {%0A if (!request) {%0A return;%0A }%0A const responseHeaders = AxiosHeaders_default.from(%0A "getAllResponseHeaders" in request && request.getAllResponseHeaders()%0A );%0A const responseData = !responseType || responseType === "text" || responseType === "json" ? request.responseText : request.response;%0A const response = {%0A data: responseData,%0A status: request.status,%0A statusText: request.statusText,%0A headers: responseHeaders,%0A config,%0A request%0A };%0A settle(function _resolve(value) {%0A resolve(value);%0A done();%0A }, function _reject(err) {%0A reject(err);%0A done();%0A }, response);%0A request = null;%0A }%0A if ("onloadend" in request) {%0A request.onloadend = onloadend;%0A } else {%0A request.onreadystatechange = function handleLoad() {%0A if (!request || request.readyState !== 4) {%0A return;%0A }%0A if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf("file:") === 0)) {%0A return;%0A }%0A setTimeout(onloadend);%0A };%0A }%0A request.onabort = function handleAbort() {%0A if (!request) {%0A return;%0A }%0A reject(new AxiosError_default("Request aborted", AxiosError_default.ECONNABORTED, config, request));%0A request = null;%0A };%0A request.onerror = function handleError() {%0A reject(new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config, request));%0A request = null;%0A };%0A request.ontimeout = function handleTimeout() {%0A let timeoutErrorMessage = config.timeout ? "timeout of " + config.timeout + "ms exceeded" : "timeout exceeded";%0A const transitional2 = config.transitional || transitional_default;%0A if (config.timeoutErrorMessage) {%0A timeoutErrorMessage = config.timeoutErrorMessage;%0A }%0A reject(new AxiosError_default(%0A timeoutErrorMessage,%0A transitional2.clarifyTimeoutError ? AxiosError_default.ETIMEDOUT : AxiosError_default.ECONNABORTED,%0A config,%0A request%0A ));%0A request = null;%0A };%0A if (browser_default.isStandardBrowserEnv) {%0A const xsrfValue = (config.withCredentials || isURLSameOrigin_default(fullPath)) && config.xsrfCookieName && cookies_default.read(config.xsrfCookieName);%0A if (xsrfValue) {%0A requestHeaders.set(config.xsrfHeaderName, xsrfValue);%0A }%0A }%0A requestData === void 0 && requestHeaders.setContentType(null);%0A if ("setRequestHeader" in request) {%0A utils_default.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {%0A request.setRequestHeader(key, val);%0A });%0A }%0A if (!utils_default.isUndefined(config.withCredentials)) {%0A request.withCredentials = !!config.withCredentials;%0A }%0A if (responseType && responseType !== "json") {%0A request.responseType = config.responseType;%0A }%0A if (typeof config.onDownloadProgress === "function") {%0A request.addEventListener("progress", progressEventReducer(config.onDownloadProgress, true));%0A }%0A if (typeof config.onUploadProgress === "function" && request.upload) {%0A request.upload.addEventListener("progress", progressEventReducer(config.onUploadProgress));%0A }%0A if (config.cancelToken || config.signal) {%0A onCanceled = (cancel) => {%0A if (!request) {%0A return;%0A }%0A reject(!cancel || cancel.type ? new CanceledError_default(null, config, request) : cancel);%0A request.abort();%0A request = null;%0A };%0A config.cancelToken && config.cancelToken.subscribe(onCanceled);%0A if (config.signal) {%0A config.signal.aborted ? onCanceled() : config.signal.addEventListener("abort", onCanceled);%0A }%0A }%0A const protocol = parseProtocol(fullPath);%0A if (protocol && browser_default.protocols.indexOf(protocol) === -1) {%0A reject(new AxiosError_default("Unsupported protocol " + protocol + ":", AxiosError_default.ERR_BAD_REQUEST, config));%0A return;%0A }%0A request.send(requestData || null);%0A });%0A};%0A%0A// node_modules/axios/lib/adapters/adapters.js%0Avar knownAdapters = {%0A http: null_default,%0A xhr: xhr_default%0A};%0Autils_default.forEach(knownAdapters, (fn, value) => {%0A if (fn) {%0A try {%0A Object.defineProperty(fn, "name", { value });%0A } catch (e) {%0A }%0A Object.defineProperty(fn, "adapterName", { value });%0A }%0A});%0Avar adapters_default = {%0A getAdapter: (adapters) => {%0A adapters = utils_default.isArray(adapters) ? adapters : [adapters];%0A const { length } = adapters;%0A let nameOrAdapter;%0A let adapter;%0A for (let i = 0; i < length; i++) {%0A nameOrAdapter = adapters[i];%0A if (adapter = utils_default.isString(nameOrAdapter) ? knownAdapters[nameOrAdapter.toLowerCase()] : nameOrAdapter) {%0A break;%0A }%0A }%0A if (!adapter) {%0A if (adapter === false) {%0A throw new AxiosError_default(%0A `Adapter ${nameOrAdapter} is not supported by the environment`,%0A "ERR_NOT_SUPPORT"%0A );%0A }%0A throw new Error(%0A utils_default.hasOwnProp(knownAdapters, nameOrAdapter) ? `Adapter \'${nameOrAdapter}\' is not available in the build` : `Unknown adapter \'${nameOrAdapter}\'`%0A );%0A }%0A if (!utils_default.isFunction(adapter)) {%0A throw new TypeError("adapter is not a function");%0A }%0A return adapter;%0A },%0A adapters: knownAdapters%0A};%0A%0A// node_modules/axios/lib/core/dispatchRequest.js%0Afunction throwIfCancellationRequested(config) {%0A if (config.cancelToken) {%0A config.cancelToken.throwIfRequested();%0A }%0A if (config.signal && config.signal.aborted) {%0A throw new CanceledError_default(null, config);%0A }%0A}%0Afunction dispatchRequest(config) {%0A throwIfCancellationRequested(config);%0A config.headers = AxiosHeaders_default.from(config.headers);%0A config.data = transformData.call(%0A config,%0A config.transformRequest%0A );%0A if (["post", "put", "patch"].indexOf(config.method) !== -1) {%0A config.headers.setContentType("application/x-www-form-urlencoded", false);%0A }%0A const adapter = adapters_default.getAdapter(config.adapter || defaults_default.adapter);%0A return adapter(config).then(function onAdapterResolution(response) {%0A throwIfCancellationRequested(config);%0A response.data = transformData.call(%0A config,%0A config.transformResponse,%0A response%0A );%0A response.headers = AxiosHeaders_default.from(response.headers);%0A return response;%0A }, function onAdapterRejection(reason) {%0A if (!isCancel(reason)) {%0A throwIfCancellationRequested(config);%0A if (reason && reason.response) {%0A reason.response.data = transformData.call(%0A config,%0A config.transformResponse,%0A reason.response%0A );%0A reason.response.headers = AxiosHeaders_default.from(reason.response.headers);%0A }%0A }%0A return Promise.reject(reason);%0A });%0A}%0A%0A// node_modules/axios/lib/core/mergeConfig.js%0Avar headersToObject = (thing) => thing instanceof AxiosHeaders_default ? thing.toJSON() : thing;%0Afunction mergeConfig(config1, config2) {%0A config2 = config2 || {};%0A const config = {};%0A function getMergedValue(target, source, caseless) {%0A if (utils_default.isPlainObject(target) && utils_default.isPlainObject(source)) {%0A return utils_default.merge.call({ caseless }, target, source);%0A } else if (utils_default.isPlainObject(source)) {%0A return utils_default.merge({}, source);%0A } else if (utils_default.isArray(source)) {%0A return source.slice();%0A }%0A return source;%0A }%0A function mergeDeepProperties(a, b, caseless) {%0A if (!utils_default.isUndefined(b)) {%0A return getMergedValue(a, b, caseless);%0A } else if (!utils_default.isUndefined(a)) {%0A return getMergedValue(void 0, a, caseless);%0A }%0A }%0A function valueFromConfig2(a, b) {%0A if (!utils_default.isUndefined(b)) {%0A return getMergedValue(void 0, b);%0A }%0A }%0A function defaultToConfig2(a, b) {%0A if (!utils_default.isUndefined(b)) {%0A return getMergedValue(void 0, b);%0A } else if (!utils_default.isUndefined(a)) {%0A return getMergedValue(void 0, a);%0A }%0A }%0A function mergeDirectKeys(a, b, prop) {%0A if (prop in config2) {%0A return getMergedValue(a, b);%0A } else if (prop in config1) {%0A return getMergedValue(void 0, a);%0A }%0A }%0A const mergeMap = {%0A url: valueFromConfig2,%0A method: valueFromConfig2,%0A data: valueFromConfig2,%0A baseURL: defaultToConfig2,%0A transformRequest: defaultToConfig2,%0A transformResponse: defaultToConfig2,%0A paramsSerializer: defaultToConfig2,%0A timeout: defaultToConfig2,%0A timeoutMessage: defaultToConfig2,%0A withCredentials: defaultToConfig2,%0A adapter: defaultToConfig2,%0A responseType: defaultToConfig2,%0A xsrfCookieName: defaultToConfig2,%0A xsrfHeaderName: defaultToConfig2,%0A onUploadProgress: defaultToConfig2,%0A onDownloadProgress: defaultToConfig2,%0A decompress: defaultToConfig2,%0A maxContentLength: defaultToConfig2,%0A maxBodyLength: defaultToConfig2,%0A beforeRedirect: defaultToConfig2,%0A transport: defaultToConfig2,%0A httpAgent: defaultToConfig2,%0A httpsAgent: defaultToConfig2,%0A cancelToken: defaultToConfig2,%0A socketPath: defaultToConfig2,%0A responseEncoding: defaultToConfig2,%0A validateStatus: mergeDirectKeys,%0A headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true)%0A };%0A utils_default.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) {%0A const merge2 = mergeMap[prop] || mergeDeepProperties;%0A const configValue = merge2(config1[prop], config2[prop], prop);%0A utils_default.isUndefined(configValue) && merge2 !== mergeDirectKeys || (config[prop] = configValue);%0A });%0A return config;%0A}%0A%0A// node_modules/axios/lib/env/data.js%0Avar VERSION = "1.4.0";%0A%0A// node_modules/axios/lib/helpers/validator.js%0Avar validators = {};%0A["object", "boolean", "number", "function", "string", "symbol"].forEach((type, i) => {%0A validators[type] = function validator(thing) {%0A return typeof thing === type || "a" + (i < 1 ? "n " : " ") + type;%0A };%0A});%0Avar deprecatedWarnings = {};%0Avalidators.transitional = function transitional(validator, version, message) {%0A function formatMessage(opt, desc) {%0A return "[Axios v" + VERSION + "] Transitional option \'" + opt + "\'" + desc + (message ? ". " + message : "");%0A }%0A return (value, opt, opts) => {%0A if (validator === false) {%0A throw new AxiosError_default(%0A formatMessage(opt, " has been removed" + (version ? " in " + version : "")),%0A AxiosError_default.ERR_DEPRECATED%0A );%0A }%0A if (version && !deprecatedWarnings[opt]) {%0A deprecatedWarnings[opt] = true;%0A console.warn(%0A formatMessage(%0A opt,%0A " has been deprecated since v" + version + " and will be removed in the near future"%0A )%0A );%0A }%0A return validator ? validator(value, opt, opts) : true;%0A };%0A};%0Afunction assertOptions(options, schema, allowUnknown) {%0A if (typeof options !== "object") {%0A throw new AxiosError_default("options must be an object", AxiosError_default.ERR_BAD_OPTION_VALUE);%0A }%0A const keys = Object.keys(options);%0A let i = keys.length;%0A while (i-- > 0) {%0A const opt = keys[i];%0A const validator = schema[opt];%0A if (validator) {%0A const value = options[opt];%0A const result = value === void 0 || validator(value, opt, options);%0A if (result !== true) {%0A throw new AxiosError_default("option " + opt + " must be " + result, AxiosError_default.ERR_BAD_OPTION_VALUE);%0A }%0A continue;%0A }%0A if (allowUnknown !== true) {%0A throw new AxiosError_default("Unknown option " + opt, AxiosError_default.ERR_BAD_OPTION);%0A }%0A }%0A}%0Avar validator_default = {%0A assertOptions,%0A validators%0A};%0A%0A// node_modules/axios/lib/core/Axios.js%0Avar validators2 = validator_default.validators;%0Avar Axios = class {%0A constructor(instanceConfig) {%0A this.defaults = instanceConfig;%0A this.interceptors = {%0A request: new InterceptorManager_default(),%0A response: new InterceptorManager_default()%0A };%0A }%0A /**%0A * Dispatch a request%0A *%0A * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)%0A * @param {?Object} config%0A *%0A * @returns {Promise} The Promise to be fulfilled%0A */%0A request(configOrUrl, config) {%0A if (typeof configOrUrl === "string") {%0A config = config || {};%0A config.url = configOrUrl;%0A } else {%0A config = configOrUrl || {};%0A }%0A config = mergeConfig(this.defaults, config);%0A const { transitional: transitional2, paramsSerializer, headers } = config;%0A if (transitional2 !== void 0) {%0A validator_default.assertOptions(transitional2, {%0A silentJSONParsing: validators2.transitional(validators2.boolean),%0A forcedJSONParsing: validators2.transitional(validators2.boolean),%0A clarifyTimeoutError: validators2.transitional(validators2.boolean)%0A }, false);%0A }%0A if (paramsSerializer != null) {%0A if (utils_default.isFunction(paramsSerializer)) {%0A config.paramsSerializer = {%0A serialize: paramsSerializer%0A };%0A } else {%0A validator_default.assertOptions(paramsSerializer, {%0A encode: validators2.function,%0A serialize: validators2.function%0A }, true);%0A }%0A }%0A config.method = (config.method || this.defaults.method || "get").toLowerCase();%0A let contextHeaders;%0A contextHeaders = headers && utils_default.merge(%0A headers.common,%0A headers[config.method]%0A );%0A contextHeaders && utils_default.forEach(%0A ["delete", "get", "head", "post", "put", "patch", "common"],%0A (method) => {%0A delete headers[method];%0A }%0A );%0A config.headers = AxiosHeaders_default.concat(contextHeaders, headers);%0A const requestInterceptorChain = [];%0A let synchronousRequestInterceptors = true;%0A this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {%0A if (typeof interceptor.runWhen === "function" && interceptor.runWhen(config) === false) {%0A return;%0A }%0A synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;%0A requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);%0A });%0A const responseInterceptorChain = [];%0A this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {%0A responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);%0A });%0A let promise;%0A let i = 0;%0A let len;%0A if (!synchronousRequestInterceptors) {%0A const chain = [dispatchRequest.bind(this), void 0];%0A chain.unshift.apply(chain, requestInterceptorChain);%0A chain.push.apply(chain, responseInterceptorChain);%0A len = chain.length;%0A promise = Promise.resolve(config);%0A while (i < len) {%0A promise = promise.then(chain[i++], chain[i++]);%0A }%0A return promise;%0A }%0A len = requestInterceptorChain.length;%0A let newConfig = config;%0A i = 0;%0A while (i < len) {%0A const onFulfilled = requestInterceptorChain[i++];%0A const onRejected = requestInterceptorChain[i++];%0A try {%0A newConfig = onFulfilled(newConfig);%0A } catch (error) {%0A onRejected.call(this, error);%0A break;%0A }%0A }%0A try {%0A promise = dispatchRequest.call(this, newConfig);%0A } catch (error) {%0A return Promise.reject(error);%0A }%0A i = 0;%0A len = responseInterceptorChain.length;%0A while (i < len) {%0A promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);%0A }%0A return promise;%0A }%0A getUri(config) {%0A config = mergeConfig(this.defaults, config);%0A const fullPath = buildFullPath(config.baseURL, config.url);%0A return buildURL(fullPath, config.params, config.paramsSerializer);%0A }%0A};%0Autils_default.forEach(["delete", "get", "head", "options"], function forEachMethodNoData2(method) {%0A Axios.prototype[method] = function(url, config) {%0A return this.request(mergeConfig(config || {}, {%0A method,%0A url,%0A data: (config || {}).data%0A }));%0A };%0A});%0Autils_default.forEach(["post", "put", "patch"], function forEachMethodWithData2(method) {%0A function generateHTTPMethod(isForm) {%0A return function httpMethod(url, data, config) {%0A return this.request(mergeConfig(config || {}, {%0A method,%0A headers: isForm ? {%0A "Content-Type": "multipart/form-data"%0A } : {},%0A url,%0A data%0A }));%0A };%0A }%0A Axios.prototype[method] = generateHTTPMethod();%0A Axios.prototype[method + "Form"] = generateHTTPMethod(true);%0A});%0Avar Axios_default = Axios;%0A%0A// node_modules/axios/lib/cancel/CancelToken.js%0Avar CancelToken = class _CancelToken {%0A constructor(executor) {%0A if (typeof executor !== "function") {%0A throw new TypeError("executor must be a function.");%0A }%0A let resolvePromise;%0A this.promise = new Promise(function promiseExecutor(resolve) {%0A resolvePromise = resolve;%0A });%0A const token = this;%0A this.promise.then((cancel) => {%0A if (!token._listeners)%0A return;%0A let i = token._listeners.length;%0A while (i-- > 0) {%0A token._listeners[i](cancel);%0A }%0A token._listeners = null;%0A });%0A this.promise.then = (onfulfilled) => {%0A let _resolve;%0A const promise = new Promise((resolve) => {%0A token.subscribe(resolve);%0A _resolve = resolve;%0A }).then(onfulfilled);%0A promise.cancel = function reject() {%0A token.unsubscribe(_resolve);%0A };%0A return promise;%0A };%0A executor(function cancel(message, config, request) {%0A if (token.reason) {%0A return;%0A }%0A token.reason = new CanceledError_default(message, config, request);%0A resolvePromise(token.reason);%0A });%0A }%0A /**%0A * Throws a `CanceledError` if cancellation has been requested.%0A */%0A throwIfRequested() {%0A if (this.reason) {%0A throw this.reason;%0A }%0A }%0A /**%0A * Subscribe to the cancel signal%0A */%0A subscribe(listener) {%0A if (this.reason) {%0A listener(this.reason);%0A return;%0A }%0A if (this._listeners) {%0A this._listeners.push(listener);%0A } else {%0A this._listeners = [listener];%0A }%0A }%0A /**%0A * Unsubscribe from the cancel signal%0A */%0A unsubscribe(listener) {%0A if (!this._listeners) {%0A return;%0A }%0A const index = this._listeners.indexOf(listener);%0A if (index !== -1) {%0A this._listeners.splice(index, 1);%0A }%0A }%0A /**%0A * Returns an object that contains a new `CancelToken` and a function that, when called,%0A * cancels the `CancelToken`.%0A */%0A static source() {%0A let cancel;%0A const token = new _CancelToken(function executor(c) {%0A cancel = c;%0A });%0A return {%0A token,%0A cancel%0A };%0A }%0A};%0Avar CancelToken_default = CancelToken;%0A%0A// node_modules/axios/lib/helpers/spread.js%0Afunction spread(callback) {%0A return function wrap(arr) {%0A return callback.apply(null, arr);%0A };%0A}%0A%0A// node_modules/axios/lib/helpers/isAxiosError.js%0Afunction isAxiosError(payload) {%0A return utils_default.isObject(payload) && payload.isAxiosError === true;%0A}%0A%0A// node_modules/axios/lib/helpers/HttpStatusCode.js%0Avar HttpStatusCode = {%0A Continue: 100,%0A SwitchingProtocols: 101,%0A Processing: 102,%0A EarlyHints: 103,%0A Ok: 200,%0A Created: 201,%0A Accepted: 202,%0A NonAuthoritativeInformation: 203,%0A NoContent: 204,%0A ResetContent: 205,%0A PartialContent: 206,%0A MultiStatus: 207,%0A AlreadyReported: 208,%0A ImUsed: 226,%0A MultipleChoices: 300,%0A MovedPermanently: 301,%0A Found: 302,%0A SeeOther: 303,%0A NotModified: 304,%0A UseProxy: 305,%0A Unused: 306,%0A TemporaryRedirect: 307,%0A PermanentRedirect: 308,%0A BadRequest: 400,%0A Unauthorized: 401,%0A PaymentRequired: 402,%0A Forbidden: 403,%0A NotFound: 404,%0A MethodNotAllowed: 405,%0A NotAcceptable: 406,%0A ProxyAuthenticationRequired: 407,%0A RequestTimeout: 408,%0A Conflict: 409,%0A Gone: 410,%0A LengthRequired: 411,%0A PreconditionFailed: 412,%0A PayloadTooLarge: 413,%0A UriTooLong: 414,%0A UnsupportedMediaType: 415,%0A RangeNotSatisfiable: 416,%0A ExpectationFailed: 417,%0A ImATeapot: 418,%0A MisdirectedRequest: 421,%0A UnprocessableEntity: 422,%0A Locked: 423,%0A FailedDependency: 424,%0A TooEarly: 425,%0A UpgradeRequired: 426,%0A PreconditionRequired: 428,%0A TooManyRequests: 429,%0A RequestHeaderFieldsTooLarge: 431,%0A UnavailableForLegalReasons: 451,%0A InternalServerError: 500,%0A NotImplemented: 501,%0A BadGateway: 502,%0A ServiceUnavailable: 503,%0A GatewayTimeout: 504,%0A HttpVersionNotSupported: 505,%0A VariantAlsoNegotiates: 506,%0A InsufficientStorage: 507,%0A LoopDetected: 508,%0A NotExtended: 510,%0A NetworkAuthenticationRequired: 511%0A};%0AObject.entries(HttpStatusCode).forEach(([key, value]) => {%0A HttpStatusCode[value] = key;%0A});%0Avar HttpStatusCode_default = HttpStatusCode;%0A%0A// node_modules/axios/lib/axios.js%0Afunction createInstance(defaultConfig) {%0A const context = new Axios_default(defaultConfig);%0A const instance2 = bind(Axios_default.prototype.request, context);%0A utils_default.extend(instance2, Axios_default.prototype, context, { allOwnKeys: true });%0A utils_default.extend(instance2, context, null, { allOwnKeys: true });%0A instance2.create = function create(instanceConfig) {%0A return createInstance(mergeConfig(defaultConfig, instanceConfig));%0A };%0A return instance2;%0A}%0Avar axios = createInstance(defaults_default);%0Aaxios.Axios = Axios_default;%0Aaxios.CanceledError = CanceledError_default;%0Aaxios.CancelToken = CancelToken_default;%0Aaxios.isCancel = isCancel;%0Aaxios.VERSION = VERSION;%0Aaxios.toFormData = toFormData_default;%0Aaxios.AxiosError = AxiosError_default;%0Aaxios.Cancel = axios.CanceledError;%0Aaxios.all = function all(promises) {%0A return Promise.all(promises);%0A};%0Aaxios.spread = spread;%0Aaxios.isAxiosError = isAxiosError;%0Aaxios.mergeConfig = mergeConfig;%0Aaxios.AxiosHeaders = AxiosHeaders_default;%0Aaxios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing);%0Aaxios.HttpStatusCode = HttpStatusCode_default;%0Aaxios.default = axios;%0Avar axios_default = axios;%0A%0A// node_modules/axios/index.js%0Avar {%0A Axios: Axios2,%0A AxiosError: AxiosError2,%0A CanceledError: CanceledError2,%0A isCancel: isCancel2,%0A CancelToken: CancelToken2,%0A VERSION: VERSION2,%0A all: all2,%0A Cancel,%0A isAxiosError: isAxiosError2,%0A spread: spread2,%0A toFormData: toFormData2,%0A AxiosHeaders: AxiosHeaders2,%0A HttpStatusCode: HttpStatusCode2,%0A formToJSON,%0A mergeConfig: mergeConfig2%0A} = axios_default;%0A%0A// node_modules/@thewtex/zstddec/dist/zstddec.modern.js%0Avar init;%0Avar instance;%0Avar heap;%0Avar IMPORT_OBJECT = {%0A env: {%0A emscripten_notify_memory_growth: function(index) {%0A heap = new Uint8Array(instance.exports.memory.buffer);%0A }%0A }%0A};%0Avar ZSTDDecoder = class {%0A init() {%0A if (init)%0A return init;%0A if (typeof fetch !== "undefined") {%0A init = fetch("data:application/wasm;base64," + wasm).then((response) => response.arrayBuffer()).then((arrayBuffer) => WebAssembly.instantiate(arrayBuffer, IMPORT_OBJECT)).then(this._init);%0A } else {%0A init = WebAssembly.instantiate(Buffer.from(wasm, "base64"), IMPORT_OBJECT).then(this._init);%0A }%0A return init;%0A }%0A _init(result) {%0A instance = result.instance;%0A IMPORT_OBJECT.env.emscripten_notify_memory_growth(0);%0A }%0A decode(array, uncompressedSize = 0) {%0A if (!instance)%0A throw new Error(`ZSTDDecoder: Await .init() before decoding.`);%0A const compressedSize = array.byteLength;%0A const compressedPtr = instance.exports.malloc(compressedSize);%0A heap.set(array, compressedPtr);%0A uncompressedSize = uncompressedSize || Number(instance.exports.ZSTD_findDecompressedSize(compressedPtr, compressedSize));%0A const uncompressedPtr = instance.exports.malloc(uncompressedSize);%0A const actualSize = instance.exports.ZSTD_decompress(uncompressedPtr, uncompressedSize, compressedPtr, compressedSize);%0A const dec = heap.slice(uncompressedPtr, uncompressedPtr + actualSize);%0A instance.exports.free(compressedPtr);%0A instance.exports.free(uncompressedPtr);%0A return dec;%0A }%0A};%0Avar wasm = "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IARrdnE2AgAgARAPGiAAIAJBCGo2AgQLzgEBBn9Bun8hCgJAIAIoAgQiCCACKAIAIglqIg0gASAAa0sNAEFsIQogCSAEIAMoAgAiC2tLDQAgACAJaiIEIAIoAggiDGshAiAAIAFBIGsiACALIAlBABAgIAMgCSALajYCAAJAAkAgBCAFayAMTwRAIAIhBQwBCyAMIAQgBmtLDQIgByAHIAIgBWsiAmoiASAIak8EQCAEIAEgCBAKGgwCCyACIAhqIQggBCABQQAgAmsQCiACayEECyAEIAAgBSAIQQEQIAsgDSEKCyAKC8cEAQJ/IAAgA2ohBgJAIANBB0wEQANAIAAgBk8NAiAAIAItAAA6AAAgAEEBaiEAIAJBAWohAgwACwALIARBAUYEQAJAIAAgAmsiBUEHTQRAIAAgAi0AADoAACAAIAItAAE6AAEgACACLQACOgACIAAgAi0AAzoAAyAAIAIgBUECdCIFQcAeaigCAGoiAigAADYABCACIAVB4B5qKAIAayECDAELIAAgAikAADcAAAsgAkEIaiECIABBCGohAAsgASAGTwRAIAAgA2ohASAEQQFHIAAgAmtBD0pyRQRAA0AgACACKQAANwAAIAJBCGohAiAAQQhqIgAgAUkNAAwDCwALIAAgAikAADcAACAAIAIpAAg3AAggA0ERSQ0BIABBEGohAANAIAAgAikAEDcAACAAIAIpABg3AAggACACKQAgNwAQIAAgAikAKDcAGCACQSBqIQIgAEEgaiIAIAFJDQALDAELAkAgACABSwRAIAAhAQwBCyABIABrIQUCQCAEQQFHIAAgAmtBD0pyRQRAIAIhAwNAIAAgAykAADcAACADQQhqIQMgAEEIaiIAIAFJDQALDAELIAAgAikAADcAACAAIAIpAAg3AAggBUERSA0AIABBEGohACACIQMDQCAAIAMpABA3AAAgACADKQAYNwAIIAAgAykAIDcAECAAIAMpACg3ABggA0EgaiEDIABBIGoiACABSQ0ACwsgAiAFaiECCwNAIAEgBk8NASABIAItAAA6AAAgAUEBaiEBIAJBAWohAgwACwALC64HAgV/AX4jAEGAAWsiESQAIBEgAzYCfEF/IQ8CQAJAAkACQAJAIAIOBAEAAwIECyAGRQRAQbh/IQ8MBAtBbCEPIAUtAAAiAiADSw0DIAggAkEC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IAggH2shBgNAAkAgBiAPTgRAQQAhAwNAIANBA0YNAiAFIANBAnQiAmpBrNABaiACIARqKAJkNgIAIANBAWohAwwACwALAkACQAJAIAQoAtwBIgMgBEHwAGogBkEHcUEMbGoiCCgCACIMaiIQIBdLDQAgByAIKAIEIgsgDGoiCmogIUsNACAKQSBqIBYgB2tNDQELIAQgCCgCCDYCKCAEIAgpAgA3AyAgByAWIARBIGogBEHcAWogFyASIBggGhAfIQoMAQsgByAMaiECIAgoAgghCCAHIAMpAAA3AAAgByADKQAINwAIAkAgDEERSQ0AIAcgAykAEDcAECAHIAMpABg3ABggDEEQa0ERSA0AIANBEGohAyAHQSBqIQwDQCAMIAMpABA3AAAgDCADKQAYNwAIIAwgAykAIDcAECAMIAMpACg3ABggA0EgaiEDIAxBIGoiDCACSQ0ACwsgAiAIayEDIAQgEDYC3AEgAiASayAISQRAIAggAiAYa0sNByAaIBogAyASayIDaiIMIAtqTwRAIAIgDCALEAoaDAILIAMgC2ohCyACIAxBACADaxAKIANrIQIgEiEDCyAIQRBPBEAgAiADKQAANwAAIAIgAykACDcACCALQRFIDQEgAiALaiEIIAJBEGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAhJDQALDAELAkAgCEEHTQRAIAIgAy0AADoAACACIAMtAAE6AAEgAiADLQACOgACIAIgAy0AAzoAAyACIAMgCEECdCIIQcAeaigCAGoiAygAADYABCADIAhB4B5qKAIAayEDDAELIAIgAykAADcAAAsgC0EJSQ0AIAIgC2ohDCACQQhqIgggA0EIaiIDa0EPTARAA0AgCCADKQAANwAAIANBCGohAyAIQQhqIgggDEkNAAwCCwALIAggAykAADcAACAIIAMpAAg3AAggC0EZSA0AIAJBGGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAxJDQALCyAKQYh/SwRAIAohCQwGBSAGQQFqIQYgByAKaiEHDAILAAsLIAQoAtwBIQMLQbp/IQkgFyADayICIBYgB2tLDQIgBwR/IAcgAyACEAIgAmoFQQALIA5rIQkMAgsgBUEANgKc6wELIAQgBSgC8OoBIgM2AtwBIAkgDmohDCADIAUoAoDrAWohEAJAIA9FBEAgDiEGDAELIAUoArjpASENIAUoArTpASETIAUoArDpASESIAVBATYChOoBQQAhAwNAIANBA0cEQCAEIANBAnQiAmogAiAFakGs0AFqKAIANgKcASADQQFqIQMMAQsLQWwhCSAEQfAAaiICIAcgBhANQYh/Sw0BIDEgAiAFKAIAEB4gMCACIAUoAggQHiAvIAIgBSgCBBAeIAxBIGshGCAOIQYDQCAEKAKIASAEKAKEAUEDdGopAgAiQKciCkEQdiIZQf8BcSELIAQoApgBIAQoApQBQQN0aikCACJBpyIWQRB2Ih9B/wFxIRogBCgCkAEgBCgCjAFBA3RqKQIAIkJCIIinIQcgQUIgiCBAQiCIpyEDAkAgQkIQiKciCEH/AXEiAkECTwRAAkAgAkEZSSA/QoGAgBBUckUEQCAEQSAgBCgCdCIIayIRIAIgAiARSxsiFyAIajYCdCAHIAQoAnAgCHRBACAXa3YgAiAXayIXdGohCCAEQfAAahAPGiACIBFNDQEgBCAEKAJ0IgIgF2o2AnQgBCgCcCACdEEAIBdrdiAIaiEIDAELIAQgAiAEKAJ0IhFqNgJ0IAQoAnAgEXRBACAIa3YgB2ohCCAEQfAAahAPGgsgBCkCnAEhRCAEIAg2ApwBIAQgRDcCoAEMAQsCQCACRQRAIAMEQCAEKAKcASEIDAMLIAQoAqABIQgMAQsgBCAEKAJ0IgJBAWo2AnQCfyAHIANFaiAEKAJwIAJ0QR92aiICQQNGBEAgBCgCnAFBAWsMAQsgAkECdCAEaigCnAELIgdFIAdqIQggAkEBRwRAIAQgBCgCoAE2AqQBCwsgBCAEKAKcATYCoAEgBCAINgKcAQunIQIgQUKAgPwHg1BFBEAgBCAEKAJ0IgcgGmo2AnQgBCgCcCAHdEEAIB9rdiACaiECCyALIBpqQRRPBEAgBEHwAGoQDxoLIEBCgID8B4NQRQRAIAQgBCgCdCIHIAtqNgJ0IAQoAnAgB3RBACAZa3YgA2ohAwsgBEHwAGoQDxogBCAEKAJwIgdBACAKQRh2IgsgBCgCdGoiGmt2IAtBAnRBoB1qKAIAcSAKQf//A3FqNgKEASAEIBogFkEYdiIKaiILNgJ0IAQgCkECdEGgHWooAgAgB0EAIAtrdnEgFkH//wNxajYClAEgBEHwAGoQDxogBCBCpyIHQRh2IgogBCgCdGoiCzYCdCAEIApBAnRBoB1qKAIAIAQoAnBBACALa3ZxIAdB//8DcWo2AowBIAQgAzYCOCAEIAI2AjwgBCAINgJAAkACQAJAIAQoAtwBIgsgA2oiFiAQSw0AIAYgAiADaiIKaiAYSw0AIApBIGogDCAGa00NAQsgBCAEQUBrKAIANgIIIAQgBCkDODcDACAGIAwgBCAEQdwBaiAQIBIgEyANEB8hCgwBCyADIAZqIQcgBiALKQAANwAAIAYgCykACDcACAJAIANBEUkNACAGIAspABA3ABAgBiALKQAYNwAYIANBEGtBEUgNACALQRBqIQMgBkEgaiELA0AgCyADKQAQNwAAIAsgAykAGDcACCALIAMpACA3ABAgCyADKQAoNwAYIANBIGohAyALQSBqIgsgB0kNAAsLIAcgCGshAyAEIBY2AtwBIAcgEmsgCEkEQCAIIAcgE2tLDQQgDSANIAMgEmsiA2oiCyACak8EQCAHIAsgAhAKGgwCCyAHIAtBACADaxAKIAQgAiADaiICNgI8IANrIQcgEiEDCyAIQRBPBEAgByADKQAANwAAIAcgAykACDcACCACQRFIDQEgAiAHaiEIIAdBEGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAhJDQALDAELAkAgCEEHTQRAIAcgAy0AADoAACAHIAMtAAE6AAEgByADLQACOgACIAcgAy0AAzoAAyAHIAMgCEECdCIIQcAeaigCAGoiAygAADYABCADIAhB4B5qKAIAayEDDAELIAcgAykAADcAAAsgAkEJSQ0AIAIgB2ohCyAHQQhqIgggA0EIaiIDa0EPTARAA0AgCCADKQAANwAAIANBCGohAyAIQQhqIgggC0kNAAwCCwALIAggAykAADcAACAIIAMpAAg3AAggAkEZSA0AIAdBGGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAtJDQALCyAKQYh/SwRAIAohCQwDCyAGIApqIQYgBEHwAGoQDyEDIA9B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";%0A%0A// dist/core/internal/loadEmscriptenModuleWebWorker.js%0Avar decoder = new ZSTDDecoder();%0Avar decoderInitialized = false;%0Aasync function loadEmscriptenModuleWebWorker(moduleRelativePathOrURL, baseUrl) {%0A let modulePrefix = null;%0A if (typeof moduleRelativePathOrURL !== "string") {%0A modulePrefix = moduleRelativePathOrURL.href;%0A } else if (moduleRelativePathOrURL.startsWith("http")) {%0A modulePrefix = moduleRelativePathOrURL;%0A } else {%0A modulePrefix = `${baseUrl}/${moduleRelativePathOrURL}`;%0A }%0A if (modulePrefix.endsWith(".js")) {%0A modulePrefix = modulePrefix.substring(0, modulePrefix.length - 3);%0A }%0A if (modulePrefix.endsWith(".wasm")) {%0A modulePrefix = modulePrefix.substring(0, modulePrefix.length - 5);%0A }%0A const wasmBinaryPath = `${modulePrefix}.wasm`;%0A const response = await axios_default.get(`${wasmBinaryPath}.zst`, { responseType: "arraybuffer" });%0A if (!decoderInitialized) {%0A await decoder.init();%0A decoderInitialized = true;%0A }%0A const decompressedArray = decoder.decode(new Uint8Array(response.data));%0A const wasmBinary = decompressedArray.buffer;%0A const modulePath = `${modulePrefix}.js`;%0A const result = await import(%0A /* webpackIgnore: true */%0A /* @vite-ignore */%0A modulePath%0A );%0A const emscriptenModule = result.default({ wasmBinary });%0A return emscriptenModule;%0A}%0Avar loadEmscriptenModuleWebWorker_default = loadEmscriptenModuleWebWorker;%0A%0A// dist/core/web-workers/load-pipeline-module.js%0Avar pipelineToModule = /* @__PURE__ */ new Map();%0Aasync function loadPipelineModule(pipelinePath, baseUrl) {%0A let moduleRelativePathOrURL = pipelinePath;%0A let pipeline = pipelinePath;%0A let pipelineModule = null;%0A if (typeof pipelinePath !== "string") {%0A moduleRelativePathOrURL = new URL(pipelinePath.href);%0A pipeline = moduleRelativePathOrURL.href;%0A }%0A if (pipelineToModule.has(pipeline)) {%0A pipelineModule = pipelineToModule.get(pipeline);%0A } else {%0A pipelineToModule.set(pipeline, await loadEmscriptenModuleWebWorker_default(moduleRelativePathOrURL, baseUrl));%0A pipelineModule = pipelineToModule.get(pipeline);%0A }%0A return pipelineModule;%0A}%0Avar load_pipeline_module_default = loadPipelineModule;%0A%0A// dist/io/internal/MimeToImageIO.js%0Avar mimeToIO = /* @__PURE__ */ new Map([%0A ["image/jpeg", "JPEGImageIO"],%0A ["image/png", "PNGImageIO"],%0A ["image/tiff", "TIFFImageIO"],%0A ["image/x-ms-bmp", "BMPImageIO"],%0A ["image/x-bmp", "BMPImageIO"],%0A ["image/bmp", "BMPImageIO"],%0A ["application/dicom", "GDCMImageIO"]%0A]);%0Avar MimeToImageIO_default = mimeToIO;%0A%0A// dist/io/extensionToImageIO.js%0Avar extensionToIO = /* @__PURE__ */ new Map([%0A ["bmp", "BMPImageIO"],%0A ["BMP", "BMPImageIO"],%0A ["dcm", "GDCMImageIO"],%0A ["DCM", "GDCMImageIO"],%0A ["gipl", "GiplImageIO"],%0A ["gipl.gz", "GiplImageIO"],%0A ["hdf5", "HDF5ImageIO"],%0A ["jpg", "JPEGImageIO"],%0A ["JPG", "JPEGImageIO"],%0A ["jpeg", "JPEGImageIO"],%0A ["JPEG", "JPEGImageIO"],%0A ["iwi", "WasmImageIO"],%0A ["iwi.cbor", "WasmImageIO"],%0A ["iwi.cbor.zst", "WasmZstdImageIO"],%0A ["lsm", "LSMImageIO"],%0A ["mnc", "MINCImageIO"],%0A ["MNC", "MINCImageIO"],%0A ["mnc.gz", "MINCImageIO"],%0A ["MNC.GZ", "MINCImageIO"],%0A ["mnc2", "MINCImageIO"],%0A ["MNC2", "MINCImageIO"],%0A ["mgh", "MGHImageIO"],%0A ["mgz", "MGHImageIO"],%0A ["mgh.gz", "MGHImageIO"],%0A ["mha", "MetaImageIO"],%0A ["mhd", "MetaImageIO"],%0A ["mrc", "MRCImageIO"],%0A ["nia", "NiftiImageIO"],%0A ["nii", "NiftiImageIO"],%0A ["nii.gz", "NiftiImageIO"],%0A ["hdr", "NiftiImageIO"],%0A ["nrrd", "NrrdImageIO"],%0A ["NRRD", "NrrdImageIO"],%0A ["nhdr", "NrrdImageIO"],%0A ["NHDR", "NrrdImageIO"],%0A ["png", "PNGImageIO"],%0A ["PNG", "PNGImageIO"],%0A ["pic", "BioRadImageIO"],%0A ["PIC", "BioRadImageIO"],%0A ["tif", "TIFFImageIO"],%0A ["TIF", "TIFFImageIO"],%0A ["tiff", "TIFFImageIO"],%0A ["TIFF", "TIFFImageIO"],%0A ["vtk", "VTKImageIO"],%0A ["VTK", "VTKImageIO"],%0A ["isq", "ScancoImageIO"],%0A ["ISQ", "ScancoImageIO"],%0A ["fdf", "FDFImageIO"],%0A ["FDF", "FDFImageIO"]%0A]);%0Avar extensionToImageIO_default = extensionToIO;%0A%0A// dist/io/getFileExtension.js%0Afunction getFileExtension(filePath) {%0A let extension = filePath.slice((filePath.lastIndexOf(".") - 1 >>> 0) + 2);%0A if (extension.toLowerCase() === "gz") {%0A const index = filePath.slice(0, -3).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A } else if (extension.toLowerCase() === "cbor") {%0A const index = filePath.slice(0, -5).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A } else if (extension.toLowerCase() === "zst") {%0A const index = filePath.slice(0, -10).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A } else if (extension.toLowerCase() === "zip") {%0A const index = filePath.slice(0, -4).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A }%0A return extension;%0A}%0Avar getFileExtension_default = getFileExtension;%0A%0A// dist/io/internal/ImageIOIndex.js%0Avar ImageIOIndex = ["PNGImageIO", "MetaImageIO", "TIFFImageIO", "NiftiImageIO", "JPEGImageIO", "NrrdImageIO", "VTKImageIO", "BMPImageIO", "HDF5ImageIO", "MINCImageIO", "MRCImageIO", "LSMImageIO", "MGHImageIO", "BioRadImageIO", "GiplImageIO", "GEAdwImageIO", "GE4ImageIO", "GE5ImageIO", "GDCMImageIO", "ScancoImageIO", "FDFImageIO", "WasmImageIO", "WasmZstdImageIO"];%0Avar ImageIOIndex_default = ImageIOIndex;%0A%0A// dist/core/InterfaceTypes.js%0Avar InterfaceTypes = {%0A // Todo: remove Interface prefix after IOTypes has been removed%0A TextFile: "InterfaceTextFile",%0A BinaryFile: "InterfaceBinaryFile",%0A TextStream: "InterfaceTextStream",%0A BinaryStream: "InterfaceBinaryStream",%0A Image: "InterfaceImage",%0A Mesh: "InterfaceMesh",%0A PolyData: "InterfacePolyData",%0A JsonCompatible: "InterfaceJsonCompatible"%0A};%0Avar InterfaceTypes_default = InterfaceTypes;%0A%0A// dist/core/IOTypes.js%0Avar IOTypes = {%0A Text: "Text",%0A Binary: "Binary",%0A Image: "Image",%0A Mesh: "Mesh"%0A};%0Avar IOTypes_default = IOTypes;%0A%0A// dist/core/interface-types/int-types.js%0Avar IntTypes = {%0A Int8: "int8",%0A UInt8: "uint8",%0A Int16: "int16",%0A UInt16: "uint16",%0A Int32: "int32",%0A UInt32: "uint32",%0A Int64: "int64",%0A UInt64: "uint64",%0A SizeValueType: "uint64",%0A IdentifierType: "uint64",%0A IndexValueType: "int64",%0A OffsetValueType: "int64"%0A};%0Avar int_types_default = IntTypes;%0A%0A// dist/core/interface-types/float-types.js%0Avar FloatTypes = {%0A Float32: "float32",%0A Float64: "float64",%0A SpacePrecisionType: "float64"%0A};%0Avar float_types_default = FloatTypes;%0A%0A// dist/core/bufferToTypedArray.js%0Afunction bufferToTypedArray(wasmType, buffer) {%0A let typedArray = null;%0A switch (wasmType) {%0A case int_types_default.UInt8: {%0A typedArray = new Uint8Array(buffer);%0A break;%0A }%0A case int_types_default.Int8: {%0A typedArray = new Int8Array(buffer);%0A break;%0A }%0A case int_types_default.UInt16: {%0A typedArray = new Uint16Array(buffer);%0A break;%0A }%0A case int_types_default.Int16: {%0A typedArray = new Int16Array(buffer);%0A break;%0A }%0A case int_types_default.UInt32: {%0A typedArray = new Uint32Array(buffer);%0A break;%0A }%0A case int_types_default.Int32: {%0A typedArray = new Int32Array(buffer);%0A break;%0A }%0A case int_types_default.UInt64: {%0A if (typeof globalThis.BigUint64Array === "function") {%0A typedArray = new BigUint64Array(buffer);%0A } else {%0A typedArray = new Uint8Array(buffer);%0A }%0A break;%0A }%0A case int_types_default.Int64: {%0A if (typeof globalThis.BigInt64Array === "function") {%0A typedArray = new BigInt64Array(buffer);%0A } else {%0A typedArray = new Uint8Array(buffer);%0A }%0A break;%0A }%0A case float_types_default.Float32: {%0A typedArray = new Float32Array(buffer);%0A break;%0A }%0A case float_types_default.Float64: {%0A typedArray = new Float64Array(buffer);%0A break;%0A }%0A case "null": {%0A typedArray = null;%0A break;%0A }%0A case null: {%0A typedArray = null;%0A break;%0A }%0A default:%0A throw new Error("Type is not supported as a TypedArray");%0A }%0A return typedArray;%0A}%0Avar bufferToTypedArray_default = bufferToTypedArray;%0A%0A// dist/pipeline/internal/runPipelineEmscripten.js%0Avar haveSharedArrayBuffer = typeof globalThis.SharedArrayBuffer === "function";%0Avar encoder = new TextEncoder();%0Avar decoder2 = new TextDecoder("utf-8");%0Afunction readFileSharedArray(emscriptenModule, path) {%0A const opts = { flags: "r", encoding: "binary" };%0A const stream = emscriptenModule.fs_open(path, opts.flags);%0A const stat = emscriptenModule.fs_stat(path);%0A const length = stat.size;%0A let arrayBufferData = null;%0A if (haveSharedArrayBuffer) {%0A arrayBufferData = new SharedArrayBuffer(length);%0A } else {%0A arrayBufferData = new ArrayBuffer(length);%0A }%0A const array = new Uint8Array(arrayBufferData);%0A emscriptenModule.fs_read(stream, array, 0, length, 0);%0A emscriptenModule.fs_close(stream);%0A return array;%0A}%0Afunction memoryUint8SharedArray(emscriptenModule, byteOffset, length) {%0A let arrayBufferData = null;%0A if (haveSharedArrayBuffer) {%0A arrayBufferData = new SharedArrayBuffer(length);%0A } else {%0A arrayBufferData = new ArrayBuffer(length);%0A }%0A const array = new Uint8Array(arrayBufferData);%0A const dataArrayView = new Uint8Array(emscriptenModule.HEAPU8.buffer, byteOffset, length);%0A array.set(dataArrayView);%0A return array;%0A}%0Afunction setPipelineModuleInputArray(emscriptenModule, dataArray, inputIndex, subIndex) {%0A let dataPtr = 0;%0A if (dataArray !== null) {%0A dataPtr = emscriptenModule.ccall("itk_wasm_input_array_alloc", "number", ["number", "number", "number", "number"], [0, inputIndex, subIndex, dataArray.buffer.byteLength]);%0A emscriptenModule.HEAPU8.set(new Uint8Array(dataArray.buffer), dataPtr);%0A }%0A return dataPtr;%0A}%0Afunction setPipelineModuleInputJSON(emscriptenModule, dataObject, inputIndex) {%0A const dataJSON = JSON.stringify(dataObject);%0A const jsonPtr = emscriptenModule.ccall("itk_wasm_input_json_alloc", "number", ["number", "number", "number"], [0, inputIndex, dataJSON.length]);%0A emscriptenModule.writeAsciiToMemory(dataJSON, jsonPtr, false);%0A}%0Afunction getPipelineModuleOutputArray(emscriptenModule, outputIndex, subIndex, componentType) {%0A const dataPtr = emscriptenModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, outputIndex, subIndex]);%0A const dataSize = emscriptenModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, outputIndex, subIndex]);%0A const dataUint8 = memoryUint8SharedArray(emscriptenModule, dataPtr, dataSize);%0A const data = bufferToTypedArray_default(componentType, dataUint8.buffer);%0A return data;%0A}%0Afunction getPipelineModuleOutputJSON(emscriptenModule, outputIndex) {%0A const jsonPtr = emscriptenModule.ccall("itk_wasm_output_json_address", "number", ["number", "number"], [0, outputIndex]);%0A const dataJSON = emscriptenModule.AsciiToString(jsonPtr);%0A const dataObject = JSON.parse(dataJSON);%0A return dataObject;%0A}%0Afunction runPipelineEmscripten(pipelineModule, args, outputs, inputs) {%0A if (!(inputs == null) && inputs.length > 0) {%0A inputs.forEach(function(input, index) {%0A var _a;%0A switch (input.type) {%0A case InterfaceTypes_default.TextStream: {%0A const dataArray = encoder.encode(input.data.data);%0A const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0);%0A const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` };%0A setPipelineModuleInputJSON(pipelineModule, dataJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.JsonCompatible: {%0A const dataArray = encoder.encode(JSON.stringify(input.data));%0A const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0);%0A const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` };%0A setPipelineModuleInputJSON(pipelineModule, dataJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.BinaryStream: {%0A const dataArray = input.data.data;%0A const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0);%0A const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` };%0A setPipelineModuleInputJSON(pipelineModule, dataJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.TextFile: {%0A pipelineModule.fs_writeFile(input.data.path, input.data.data);%0A break;%0A }%0A case InterfaceTypes_default.BinaryFile: {%0A pipelineModule.fs_writeFile(input.data.path, input.data.data);%0A break;%0A }%0A case InterfaceTypes_default.Image: {%0A const image = input.data;%0A const dataPtr = setPipelineModuleInputArray(pipelineModule, image.data, index, 0);%0A const directionPtr = setPipelineModuleInputArray(pipelineModule, image.direction, index, 1);%0A const metadata = typeof ((_a = image.metadata) === null || _a === void 0 ? void 0 : _a.entries) !== "undefined" ? JSON.stringify(Array.from(image.metadata.entries())) : "[]";%0A const imageJSON = {%0A imageType: image.imageType,%0A name: image.name,%0A origin: image.origin,%0A spacing: image.spacing,%0A direction: `data:application/vnd.itk.address,0:${directionPtr}`,%0A size: image.size,%0A data: `data:application/vnd.itk.address,0:${dataPtr}`,%0A metadata%0A };%0A setPipelineModuleInputJSON(pipelineModule, imageJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.Mesh: {%0A const mesh = input.data;%0A const pointsPtr = setPipelineModuleInputArray(pipelineModule, mesh.points, index, 0);%0A const cellsPtr = setPipelineModuleInputArray(pipelineModule, mesh.cells, index, 1);%0A const pointDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.pointData, index, 2);%0A const cellDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.cellData, index, 3);%0A const meshJSON = {%0A meshType: mesh.meshType,%0A name: mesh.name,%0A numberOfPoints: mesh.numberOfPoints,%0A points: `data:application/vnd.itk.address,0:${pointsPtr}`,%0A numberOfCells: mesh.numberOfCells,%0A cells: `data:application/vnd.itk.address,0:${cellsPtr}`,%0A cellBufferSize: mesh.cellBufferSize,%0A numberOfPointPixels: mesh.numberOfPointPixels,%0A pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`,%0A numberOfCellPixels: mesh.numberOfCellPixels,%0A cellData: `data:application/vnd.itk.address,0:${cellDataPtr}`%0A };%0A setPipelineModuleInputJSON(pipelineModule, meshJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.PolyData: {%0A const polyData = input.data;%0A const pointsPtr = setPipelineModuleInputArray(pipelineModule, polyData.points, index, 0);%0A const verticesPtr = setPipelineModuleInputArray(pipelineModule, polyData.vertices, index, 1);%0A const linesPtr = setPipelineModuleInputArray(pipelineModule, polyData.lines, index, 2);%0A const polygonsPtr = setPipelineModuleInputArray(pipelineModule, polyData.polygons, index, 3);%0A const triangleStripsPtr = setPipelineModuleInputArray(pipelineModule, polyData.triangleStrips, index, 4);%0A const pointDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 5);%0A const cellDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 6);%0A const polyDataJSON = {%0A polyDataType: polyData.polyDataType,%0A name: polyData.name,%0A numberOfPoints: polyData.numberOfPoints,%0A points: `data:application/vnd.itk.address,0:${pointsPtr}`,%0A verticesBufferSize: polyData.verticesBufferSize,%0A vertices: `data:application/vnd.itk.address,0:${verticesPtr}`,%0A linesBufferSize: polyData.linesBufferSize,%0A lines: `data:application/vnd.itk.address,0:${linesPtr}`,%0A polygonsBufferSize: polyData.polygonsBufferSize,%0A polygons: `data:application/vnd.itk.address,0:${polygonsPtr}`,%0A triangleStripsBufferSize: polyData.triangleStripsBufferSize,%0A triangleStrips: `data:application/vnd.itk.address,0:${triangleStripsPtr}`,%0A numberOfPointPixels: polyData.numberOfPointPixels,%0A pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`,%0A numberOfCellPixels: polyData.numberOfCellPixels,%0A cellData: `data:application/vnd.itk.address,0:${cellDataPtr}`%0A };%0A setPipelineModuleInputJSON(pipelineModule, polyDataJSON, index);%0A break;%0A }%0A case IOTypes_default.Text: {%0A pipelineModule.fs_writeFile(input.path, input.data);%0A break;%0A }%0A case IOTypes_default.Binary: {%0A pipelineModule.fs_writeFile(input.path, input.data);%0A break;%0A }%0A case IOTypes_default.Image: {%0A const image = input.data;%0A const imageJSON = {%0A imageType: image.imageType,%0A name: image.name,%0A origin: image.origin,%0A spacing: image.spacing,%0A direction: "data:application/vnd.itk.path,data/direction.raw",%0A size: image.size,%0A data: "data:application/vnd.itk.path,data/data.raw"%0A };%0A pipelineModule.fs_mkdirs(`${input.path}/data`);%0A pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(imageJSON));%0A if (image.data === null) {%0A throw Error("image.data is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/data.raw`, new Uint8Array(image.data.buffer));%0A pipelineModule.fs_writeFile(`${input.path}/data/direction.raw`, new Uint8Array(image.direction.buffer));%0A break;%0A }%0A case IOTypes_default.Mesh: {%0A const mesh = input.data;%0A const meshJSON = {%0A meshType: mesh.meshType,%0A name: mesh.name,%0A numberOfPoints: mesh.numberOfPoints,%0A points: "data:application/vnd.itk.path,data/points.raw",%0A numberOfPointPixels: mesh.numberOfPointPixels,%0A pointData: "data:application/vnd.itk.path,data/pointData.raw",%0A numberOfCells: mesh.numberOfCells,%0A cells: "data:application/vnd.itk.path,data/cells.raw",%0A numberOfCellPixels: mesh.numberOfCellPixels,%0A cellData: "data:application/vnd.itk.path,data/cellData.raw",%0A cellBufferSize: mesh.cellBufferSize%0A };%0A pipelineModule.fs_mkdirs(`${input.path}/data`);%0A pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(meshJSON));%0A if (meshJSON.numberOfPoints > 0) {%0A if (mesh.points === null) {%0A throw Error("mesh.points is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/points.raw`, new Uint8Array(mesh.points.buffer));%0A }%0A if (meshJSON.numberOfPointPixels > 0) {%0A if (mesh.pointData === null) {%0A throw Error("mesh.pointData is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/pointData.raw`, new Uint8Array(mesh.pointData.buffer));%0A }%0A if (meshJSON.numberOfCells > 0) {%0A if (mesh.cells === null) {%0A throw Error("mesh.cells is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/cells.raw`, new Uint8Array(mesh.cells.buffer));%0A }%0A if (meshJSON.numberOfCellPixels > 0) {%0A if (mesh.cellData === null) {%0A throw Error("mesh.cellData is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/cellData.raw`, new Uint8Array(mesh.cellData.buffer));%0A }%0A break;%0A }%0A default:%0A throw Error("Unsupported input InterfaceType");%0A }%0A });%0A }%0A pipelineModule.resetModuleStdout();%0A pipelineModule.resetModuleStderr();%0A const stackPtr = pipelineModule.stackSave();%0A let returnValue = 0;%0A try {%0A returnValue = pipelineModule.callMain(args.slice());%0A } catch (exception) {%0A if (typeof exception === "number") {%0A console.log("Exception while running pipeline:");%0A console.log("stdout:", pipelineModule.getModuleStdout());%0A console.error("stderr:", pipelineModule.getModuleStderr());%0A if (typeof pipelineModule.getExceptionMessage !== "undefined") {%0A console.error("exception:", pipelineModule.getExceptionMessage(exception));%0A } else {%0A console.error("Build module in Debug mode for exception message information.");%0A }%0A }%0A throw exception;%0A } finally {%0A pipelineModule.stackRestore(stackPtr);%0A }%0A const stdout = pipelineModule.getModuleStdout();%0A const stderr = pipelineModule.getModuleStderr();%0A const populatedOutputs = [];%0A if (!(outputs == null) && outputs.length > 0 && returnValue === 0) {%0A outputs.forEach(function(output, index) {%0A let outputData = null;%0A switch (output.type) {%0A case InterfaceTypes_default.TextStream: {%0A const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize);%0A outputData = { data: decoder2.decode(dataArrayView) };%0A break;%0A }%0A case InterfaceTypes_default.JsonCompatible: {%0A const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize);%0A outputData = JSON.parse(decoder2.decode(dataArrayView));%0A break;%0A }%0A case InterfaceTypes_default.BinaryStream: {%0A const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]);%0A outputData = { data: memoryUint8SharedArray(pipelineModule, dataPtr, dataSize) };%0A break;%0A }%0A case InterfaceTypes_default.TextFile: {%0A outputData = { path: output.data.path, data: pipelineModule.fs_readFile(output.data.path, { encoding: "utf8" }) };%0A break;%0A }%0A case InterfaceTypes_default.BinaryFile: {%0A outputData = { path: output.data.path, data: readFileSharedArray(pipelineModule, output.data.path) };%0A break;%0A }%0A case InterfaceTypes_default.Image: {%0A const image = getPipelineModuleOutputJSON(pipelineModule, index);%0A image.data = getPipelineModuleOutputArray(pipelineModule, index, 0, image.imageType.componentType);%0A image.direction = getPipelineModuleOutputArray(pipelineModule, index, 1, float_types_default.Float64);%0A image.metadata = new Map(image.metadata);%0A outputData = image;%0A break;%0A }%0A case InterfaceTypes_default.Mesh: {%0A const mesh = getPipelineModuleOutputJSON(pipelineModule, index);%0A if (mesh.numberOfPoints > 0) {%0A mesh.points = getPipelineModuleOutputArray(pipelineModule, index, 0, mesh.meshType.pointComponentType);%0A } else {%0A mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCells > 0) {%0A mesh.cells = getPipelineModuleOutputArray(pipelineModule, index, 1, mesh.meshType.cellComponentType);%0A } else {%0A mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfPointPixels > 0) {%0A mesh.pointData = getPipelineModuleOutputArray(pipelineModule, index, 2, mesh.meshType.pointPixelComponentType);%0A } else {%0A mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCellPixels > 0) {%0A mesh.cellData = getPipelineModuleOutputArray(pipelineModule, index, 3, mesh.meshType.cellPixelComponentType);%0A } else {%0A mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0));%0A }%0A outputData = mesh;%0A break;%0A }%0A case InterfaceTypes_default.PolyData: {%0A const polyData = getPipelineModuleOutputJSON(pipelineModule, index);%0A if (polyData.numberOfPoints > 0) {%0A polyData.points = getPipelineModuleOutputArray(pipelineModule, index, 0, float_types_default.Float32);%0A } else {%0A polyData.points = new Float32Array();%0A }%0A if (polyData.verticesBufferSize > 0) {%0A polyData.vertices = getPipelineModuleOutputArray(pipelineModule, index, 1, int_types_default.UInt32);%0A } else {%0A polyData.vertices = new Uint32Array();%0A }%0A if (polyData.linesBufferSize > 0) {%0A polyData.lines = getPipelineModuleOutputArray(pipelineModule, index, 2, int_types_default.UInt32);%0A } else {%0A polyData.lines = new Uint32Array();%0A }%0A if (polyData.polygonsBufferSize > 0) {%0A polyData.polygons = getPipelineModuleOutputArray(pipelineModule, index, 3, int_types_default.UInt32);%0A } else {%0A polyData.polygons = new Uint32Array();%0A }%0A if (polyData.triangleStripsBufferSize > 0) {%0A polyData.triangleStrips = getPipelineModuleOutputArray(pipelineModule, index, 4, int_types_default.UInt32);%0A } else {%0A polyData.triangleStrips = new Uint32Array();%0A }%0A if (polyData.numberOfPointPixels > 0) {%0A polyData.pointData = getPipelineModuleOutputArray(pipelineModule, index, 5, polyData.polyDataType.pointPixelComponentType);%0A } else {%0A polyData.pointData = bufferToTypedArray_default(polyData.polyDataType.pointPixelComponentType, new ArrayBuffer(0));%0A }%0A if (polyData.numberOfCellPixels > 0) {%0A polyData.cellData = getPipelineModuleOutputArray(pipelineModule, index, 6, polyData.polyDataType.cellPixelComponentType);%0A } else {%0A polyData.cellData = bufferToTypedArray_default(polyData.polyDataType.cellPixelComponentType, new ArrayBuffer(0));%0A }%0A outputData = polyData;%0A break;%0A }%0A case IOTypes_default.Text: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A outputData = pipelineModule.fs_readFile(output.path, { encoding: "utf8" });%0A break;%0A }%0A case IOTypes_default.Binary: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A outputData = readFileSharedArray(pipelineModule, output.path);%0A break;%0A }%0A case IOTypes_default.Image: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A const imageJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" });%0A const image = JSON.parse(imageJSON);%0A const dataUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/data.raw`);%0A image.data = bufferToTypedArray_default(image.imageType.componentType, dataUint8.buffer);%0A const directionUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/direction.raw`);%0A image.direction = bufferToTypedArray_default(float_types_default.Float64, directionUint8.buffer);%0A outputData = image;%0A break;%0A }%0A case IOTypes_default.Mesh: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A const meshJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" });%0A const mesh = JSON.parse(meshJSON);%0A if (mesh.numberOfPoints > 0) {%0A const dataUint8Points = readFileSharedArray(pipelineModule, `${output.path}/data/points.raw`);%0A mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, dataUint8Points.buffer);%0A } else {%0A mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfPointPixels > 0) {%0A const dataUint8PointData = readFileSharedArray(pipelineModule, `${output.path}/data/pointData.raw`);%0A mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, dataUint8PointData.buffer);%0A } else {%0A mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCells > 0) {%0A const dataUint8Cells = readFileSharedArray(pipelineModule, `${output.path}/data/cells.raw`);%0A mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, dataUint8Cells.buffer);%0A } else {%0A mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCellPixels > 0) {%0A const dataUint8CellData = readFileSharedArray(pipelineModule, `${output.path}/data/cellData.raw`);%0A mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, dataUint8CellData.buffer);%0A } else {%0A mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0));%0A }%0A outputData = mesh;%0A break;%0A }%0A default:%0A throw Error("Unsupported output InterfaceType");%0A }%0A const populatedOutput = {%0A type: output.type,%0A data: outputData%0A };%0A populatedOutputs.push(populatedOutput);%0A });%0A }%0A return { returnValue, stdout, stderr, outputs: populatedOutputs };%0A}%0Avar runPipelineEmscripten_default = runPipelineEmscripten;%0A%0A// dist/core/web-workers/load-image-io-pipeline-module.js%0Avar __await = function(v) {%0A return this instanceof __await ? (this.v = v, this) : new __await(v);%0A};%0Avar __asyncGenerator = function(thisArg, _arguments, generator) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var g = generator.apply(thisArg, _arguments || []), i, q = [];%0A return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i;%0A function verb(n) {%0A if (g[n])%0A i[n] = function(v) {%0A return new Promise(function(a, b) {%0A q.push([n, v, a, b]) > 1 || resume(n, v);%0A });%0A };%0A }%0A function resume(n, v) {%0A try {%0A step(g[n](v));%0A } catch (e) {%0A settle2(q[0][3], e);%0A }%0A }%0A function step(r) {%0A r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle2(q[0][2], r);%0A }%0A function fulfill(value) {%0A resume("next", value);%0A }%0A function reject(value) {%0A resume("throw", value);%0A }%0A function settle2(f, v) {%0A if (f(v), q.shift(), q.length)%0A resume(q[0][0], q[0][1]);%0A }%0A};%0Avar __asyncValues = function(o) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var m = o[Symbol.asyncIterator], i;%0A return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i);%0A function verb(n) {%0A i[n] = o[n] && function(v) {%0A return new Promise(function(resolve, reject) {%0A v = o[n](v), settle2(resolve, reject, v.done, v.value);%0A });%0A };%0A }%0A function settle2(resolve, reject, d, v) {%0A Promise.resolve(v).then(function(v2) {%0A resolve({ value: v2, done: d });%0A }, reject);%0A }%0A};%0Afunction availableIOModules(input) {%0A return __asyncGenerator(this, arguments, function* availableIOModules_1() {%0A for (let idx = 0; idx < ImageIOIndex_default.length; idx++) {%0A const trialIO = ImageIOIndex_default[idx] + "-read-image";%0A const ioModule = yield __await(load_pipeline_module_default(trialIO, input.config.imageIOUrl));%0A yield yield __await(ioModule);%0A }%0A });%0A}%0Aasync function loadImageIOPipelineModule(input, postfix) {%0A var e_1, _a;%0A if (input.mimeType && MimeToImageIO_default.has(input.mimeType)) {%0A const io = MimeToImageIO_default.get(input.mimeType) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.imageIOUrl);%0A return ioModule;%0A }%0A const extension = getFileExtension_default(input.fileName);%0A if (extensionToImageIO_default.has(extension)) {%0A const io = extensionToImageIO_default.get(extension) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.imageIOUrl);%0A return ioModule;%0A }%0A for (let idx = 0; idx < ImageIOIndex_default.length; ++idx) {%0A let idx2 = 0;%0A try {%0A for (var _b = (e_1 = void 0, __asyncValues(availableIOModules(input))), _c; _c = await _b.next(), !_c.done; ) {%0A const pipelineModule = _c.value;%0A try {%0A const { returnValue, outputs } = await runPipelineEmscripten_default(pipelineModule, input.args, input.outputs, input.inputs);%0A if (returnValue === 0) {%0A return pipelineModule;%0A }%0A } catch (error) {%0A }%0A idx2++;%0A }%0A } catch (e_1_1) {%0A e_1 = { error: e_1_1 };%0A } finally {%0A try {%0A if (_c && !_c.done && (_a = _b.return))%0A await _a.call(_b);%0A } finally {%0A if (e_1)%0A throw e_1.error;%0A }%0A }%0A }%0A throw Error(`Could not find IO for: ${input.fileName}`);%0A}%0Avar load_image_io_pipeline_module_default = loadImageIOPipelineModule;%0A%0A// dist/io/internal/MimeToMeshIO.js%0Avar mimeToIO2 = /* @__PURE__ */ new Map([]);%0Avar MimeToMeshIO_default = mimeToIO2;%0A%0A// dist/io/extensionToMeshIO.js%0Avar extensionToIO2 = /* @__PURE__ */ new Map([%0A ["vtk", "VTKPolyDataMeshIO"],%0A ["VTK", "VTKPolyDataMeshIO"],%0A ["byu", "BYUMeshIO"],%0A ["BYU", "BYUMeshIO"],%0A ["fsa", "FreeSurferAsciiMeshIO"],%0A ["FSA", "FreeSurferAsciiMeshIO"],%0A ["fsb", "FreeSurferBinaryMeshIO"],%0A ["FSB", "FreeSurferBinaryMeshIO"],%0A ["obj", "OBJMeshIO"],%0A ["OBJ", "OBJMeshIO"],%0A ["off", "OFFMeshIO"],%0A ["OFF", "OFFMeshIO"],%0A ["stl", "STLMeshIO"],%0A ["STL", "STLMeshIO"],%0A ["swc", "SWCMeshIO"],%0A ["SWC", "SWCMeshIO"],%0A ["iwm", "WasmMeshIO"],%0A ["iwm.cbor", "WasmMeshIO"],%0A ["iwm.cbor.zst", "WasmZstdMeshIO"]%0A]);%0Avar extensionToMeshIO_default = extensionToIO2;%0A%0A// dist/io/internal/MeshIOIndex.js%0Avar MeshIOIndex = ["BYUMeshIO", "FreeSurferAsciiMeshIO", "FreeSurferBinaryMeshIO", "OBJMeshIO", "OFFMeshIO", "STLMeshIO", "SWCMeshIO", "VTKPolyDataMeshIO", "WasmMeshIO", "WasmZstdMeshIO"];%0Avar MeshIOIndex_default = MeshIOIndex;%0A%0A// dist/core/web-workers/load-mesh-io-pipeline-module.js%0Avar __await2 = function(v) {%0A return this instanceof __await2 ? (this.v = v, this) : new __await2(v);%0A};%0Avar __asyncGenerator2 = function(thisArg, _arguments, generator) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var g = generator.apply(thisArg, _arguments || []), i, q = [];%0A return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i;%0A function verb(n) {%0A if (g[n])%0A i[n] = function(v) {%0A return new Promise(function(a, b) {%0A q.push([n, v, a, b]) > 1 || resume(n, v);%0A });%0A };%0A }%0A function resume(n, v) {%0A try {%0A step(g[n](v));%0A } catch (e) {%0A settle2(q[0][3], e);%0A }%0A }%0A function step(r) {%0A r.value instanceof __await2 ? Promise.resolve(r.value.v).then(fulfill, reject) : settle2(q[0][2], r);%0A }%0A function fulfill(value) {%0A resume("next", value);%0A }%0A function reject(value) {%0A resume("throw", value);%0A }%0A function settle2(f, v) {%0A if (f(v), q.shift(), q.length)%0A resume(q[0][0], q[0][1]);%0A }%0A};%0Avar __asyncValues2 = function(o) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var m = o[Symbol.asyncIterator], i;%0A return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i);%0A function verb(n) {%0A i[n] = o[n] && function(v) {%0A return new Promise(function(resolve, reject) {%0A v = o[n](v), settle2(resolve, reject, v.done, v.value);%0A });%0A };%0A }%0A function settle2(resolve, reject, d, v) {%0A Promise.resolve(v).then(function(v2) {%0A resolve({ value: v2, done: d });%0A }, reject);%0A }%0A};%0Afunction availableIOModules2(input) {%0A return __asyncGenerator2(this, arguments, function* availableIOModules_1() {%0A for (let idx = 0; idx < MeshIOIndex_default.length; idx++) {%0A const trialIO = MeshIOIndex_default[idx] + "-read-mesh";%0A const ioModule = yield __await2(load_pipeline_module_default(trialIO, input.config.meshIOUrl));%0A yield yield __await2(ioModule);%0A }%0A });%0A}%0Aasync function loadMeshIOPipelineModule(input, postfix) {%0A var e_1, _a;%0A if (input.mimeType && MimeToMeshIO_default.has(input.mimeType)) {%0A const io = MimeToMeshIO_default.get(input.mimeType) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.meshIOUrl);%0A return ioModule;%0A }%0A const extension = getFileExtension_default(input.fileName);%0A if (extensionToMeshIO_default.has(extension)) {%0A const io = extensionToMeshIO_default.get(extension) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.meshIOUrl);%0A return ioModule;%0A }%0A for (let idx = 0; idx < MeshIOIndex_default.length; ++idx) {%0A let idx2 = 0;%0A try {%0A for (var _b = (e_1 = void 0, __asyncValues2(availableIOModules2(input))), _c; _c = await _b.next(), !_c.done; ) {%0A const pipelineModule = _c.value;%0A try {%0A const { returnValue, outputs } = await runPipelineEmscripten_default(pipelineModule, input.args, input.outputs, input.inputs);%0A if (returnValue === 0) {%0A return pipelineModule;%0A }%0A } catch (error) {%0A }%0A idx2++;%0A }%0A } catch (e_1_1) {%0A e_1 = { error: e_1_1 };%0A } finally {%0A try {%0A if (_c && !_c.done && (_a = _b.return))%0A await _a.call(_b);%0A } finally {%0A if (e_1)%0A throw e_1.error;%0A }%0A }%0A }%0A throw Error(`Could not find IO for: ${input.fileName}`);%0A}%0Avar load_mesh_io_pipeline_module_default = loadMeshIOPipelineModule;%0A%0A// dist/core/web-workers/run-pipeline.js%0Avar import_register = __toESM(require_register(), 1);%0A%0A// dist/core/getTransferables.js%0Avar haveSharedArrayBuffer2 = typeof globalThis.SharedArrayBuffer !== "undefined";%0Afunction getTransferables(data) {%0A if (data === void 0 || data === null) {%0A return [];%0A }%0A const transferables = [];%0A for (let i = 0; i < data.length; i++) {%0A const transferable = getTransferable(data[i]);%0A if (transferable !== null) {%0A transferables.push(transferable);%0A }%0A }%0A return transferables;%0A}%0Afunction getTransferable(data) {%0A if (data === void 0 || data === null) {%0A return null;%0A }%0A let result = null;%0A if (data.buffer !== void 0) {%0A result = data.buffer;%0A } else if (data.byteLength !== void 0) {%0A result = data;%0A }%0A if (haveSharedArrayBuffer2 && result instanceof SharedArrayBuffer) {%0A return null;%0A }%0A return result;%0A}%0Avar getTransferables_default = getTransferables;%0A%0A// dist/core/internal/imageTransferables.js%0Afunction imageTransferables(image) {%0A return [%0A image.data,%0A image.direction%0A ];%0A}%0Avar imageTransferables_default = imageTransferables;%0A%0A// dist/core/internal/meshTransferables.js%0Afunction meshTransferables(mesh) {%0A return [%0A mesh.points,%0A mesh.pointData,%0A mesh.cells,%0A mesh.cellData%0A ];%0A}%0Avar meshTransferables_default = meshTransferables;%0A%0A// dist/core/internal/polyDataTransferables.js%0Afunction polyDataTransferables(polyData) {%0A return [%0A polyData.points,%0A polyData.vertices,%0A polyData.lines,%0A polyData.polygons,%0A polyData.triangleStrips,%0A polyData.pointData,%0A polyData.cellData%0A ];%0A}%0Avar polyDataTransferables_default = polyDataTransferables;%0A%0A// dist/core/web-workers/run-pipeline.js%0Aasync function runPipeline(pipelineModule, args, outputs, inputs) {%0A const result = runPipelineEmscripten_default(pipelineModule, args, outputs, inputs);%0A const transferables = [];%0A if (result.outputs) {%0A result.outputs.forEach(function(output) {%0A if (output.type === InterfaceTypes_default.BinaryStream || output.type === InterfaceTypes_default.BinaryFile) {%0A const binary = output.data;%0A transferables.push(binary);%0A } else if (output.type === InterfaceTypes_default.Image) {%0A const image = output.data;%0A transferables.push(...imageTransferables_default(image));%0A } else if (output.type === InterfaceTypes_default.Mesh) {%0A const mesh = output.data;%0A transferables.push(...meshTransferables_default(mesh));%0A } else if (output.type === InterfaceTypes_default.PolyData) {%0A const polyData = output.data;%0A transferables.push(...polyDataTransferables_default(polyData));%0A } else if (output.type === IOTypes_default.Binary) {%0A const binary = output.data;%0A transferables.push(binary);%0A } else if (output.type === IOTypes_default.Image) {%0A const image = output.data;%0A transferables.push(...imageTransferables_default(image));%0A } else if (output.type === IOTypes_default.Mesh) {%0A const mesh = output.data;%0A transferables.push(...meshTransferables_default(mesh));%0A }%0A });%0A }%0A return new import_register.default.TransferableResponse(result, getTransferables_default(transferables));%0A}%0Avar run_pipeline_default = runPipeline;%0A%0A// dist/core/web-workers/itk-wasm-pipeline.worker.js%0A(0, import_register2.default)(async function(input) {%0A let pipelineModule = null;%0A if (input.operation === "runPipeline") {%0A const pipelineBaseUrl = typeof input.config[input.pipelineBaseUrl] === "undefined" ? input.pipelineBaseUrl : input.config[input.pipelineBaseUrl];%0A pipelineModule = await load_pipeline_module_default(input.pipelinePath, pipelineBaseUrl);%0A } else if (input.operation === "readImage") {%0A pipelineModule = await load_image_io_pipeline_module_default(input, "-read-image");%0A } else if (input.operation === "writeImage") {%0A pipelineModule = await load_image_io_pipeline_module_default(input, "-write-image");%0A } else if (input.operation === "readMesh") {%0A pipelineModule = await load_mesh_io_pipeline_module_default(input, "-read-mesh");%0A } else if (input.operation === "writeMesh") {%0A pipelineModule = await load_mesh_io_pipeline_module_default(input, "-write-mesh");%0A } else if (input.operation === "meshToPolyData") {%0A pipelineModule = await load_pipeline_module_default("mesh-to-polydata", input.config.meshIOUrl);%0A } else if (input.operation === "polyDataToMesh") {%0A pipelineModule = await load_pipeline_module_default("polydata-to-mesh", input.config.meshIOUrl);%0A } else if (input.operation === "readDICOMImageSeries") {%0A pipelineModule = await load_pipeline_module_default("read-image-dicom-file-series", input.config.imageIOUrl);%0A } else if (input.operation === "readDICOMTags") {%0A pipelineModule = await load_pipeline_module_default("read-dicom-tags", input.config.imageIOUrl);%0A } else {%0A throw new Error("Unknown worker operation");%0A }%0A return run_pipeline_default(pipelineModule, input.args, input.outputs, input.inputs);%0A});%0A'; + +// src/index-worker-embedded.ts +setPipelineWorkerUrl(itk_wasm_pipeline_worker_default); +export { + bio_rad_read_image_default as bioRadReadImage, + bio_rad_write_image_default as bioRadWriteImage, + bmp_read_image_default as bmpReadImage, + bmp_write_image_default as bmpWriteImage, + fdf_read_image_default as fdfReadImage, + fdf_write_image_default as fdfWriteImage, + gdcm_read_image_default as gdcmReadImage, + gdcm_write_image_default as gdcmWriteImage, + ge4_read_image_default as ge4ReadImage, + ge4_write_image_default as ge4WriteImage, + ge5_read_image_default as ge5ReadImage, + ge5_write_image_default as ge5WriteImage, + ge_adw_read_image_default as geAdwReadImage, + ge_adw_write_image_default as geAdwWriteImage, + getPipelineWorkerUrl2 as getPipelineWorkerUrl, + getPipelinesBaseUrl2 as getPipelinesBaseUrl, + gipl_read_image_default as giplReadImage, + gipl_write_image_default as giplWriteImage, + hdf5_read_image_default as hdf5ReadImage, + hdf5_write_image_default as hdf5WriteImage, + jpeg_read_image_default as jpegReadImage, + jpeg_write_image_default as jpegWriteImage, + lsm_read_image_default as lsmReadImage, + lsm_write_image_default as lsmWriteImage, + meta_read_image_default as metaReadImage, + meta_write_image_default as metaWriteImage, + mgh_read_image_default as mghReadImage, + mgh_write_image_default as mghWriteImage, + minc_read_image_default as mincReadImage, + minc_write_image_default as mincWriteImage, + mrc_read_image_default as mrcReadImage, + mrc_write_image_default as mrcWriteImage, + nifti_read_image_default as niftiReadImage, + nifti_write_image_default as niftiWriteImage, + nrrd_read_image_default as nrrdReadImage, + nrrd_write_image_default as nrrdWriteImage, + png_read_image_default as pngReadImage, + png_write_image_default as pngWriteImage, + read_image_default as readImage, + read_image_file_series_default as readImageFileSeries, + scanco_read_image_default as scancoReadImage, + scanco_write_image_default as scancoWriteImage, + setPipelineWorkerUrl, + setPipelinesBaseUrl, + tiff_read_image_default as tiffReadImage, + tiff_write_image_default as tiffWriteImage, + vtk_read_image_default as vtkReadImage, + vtk_write_image_default as vtkWriteImage, + wasm_read_image_default as wasmReadImage, + wasm_write_image_default as wasmWriteImage, + wasm_zstd_read_image_default as wasmZstdReadImage, + wasm_zstd_write_image_default as wasmZstdWriteImage, + write_image_default as writeImage +}; +""" +default_config = JsPackageConfig(default_js_module) +js_package = JsPackage(default_config) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml b/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml new file mode 100644 index 000000000..8f4db83bf --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml @@ -0,0 +1,72 @@ +[build-system] +requires = ["hatchling", "hatch-vcs"] +build-backend = "hatchling.build" + +[project] +name = "itkwasm-image-io-emscripten" +readme = "README.md" +license = "Apache-2.0" +dynamic = ["version"] +description = "Input and output for scientific and medical image file formats." +classifiers = [ + "License :: OSI Approved :: Apache Software License", + "Programming Language :: Python", + "Programming Language :: C++", + "Environment :: WebAssembly", + "Environment :: WebAssembly :: Emscripten", + "Environment :: WebAssembly :: WASI", + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "Intended Audience :: Science/Research", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", +] +keywords = [ + "itkwasm", + "webassembly", + "emscripten", +] + +requires-python = ">=3.8" +dependencies = [ + "itkwasm >= 1.0.b131", +] + +[tool.hatch.version] +path = "itkwasm_image_io_emscripten/_version.py" + +[tool.hatch.envs.default] +dependencies = [ + "pytest", + "pytest-pyodide", +] + +[project.urls] +Home = "https://github.com/InsightSoftwareConsortium/itk-wasm" +Source = "https://github.com/InsightSoftwareConsortium/itk-wasm" + +[tool.hatch.envs.default.scripts] +test = [ + "hatch build -t wheel", + "pytest --dist-dir=./dist --rt=chrome", +] +download-pyodide = [ + "curl -L https://github.com/pyodide/pyodide/releases/download/0.24.1/pyodide-0.24.1.tar.bz2 -o pyodide.tar.bz2", + "tar xjf pyodide.tar.bz2", + "rm -rf dist pyodide.tar.bz2", + "mv pyodide dist", +] +serve = [ + "hatch build -t wheel", + 'echo "\nVisit http://localhost:8877/console.html\n"', + "python -m http.server --directory=./dist 8877", +] + + +[tool.hatch.build] +exclude = [ + "/examples", +] diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/__init__.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/test_itkwasm_image_io.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_itkwasm_image_io.py new file mode 100644 index 000000000..b61e180fa --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_itkwasm_image_io.py @@ -0,0 +1,20 @@ +import pytest +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide + +from itkwasm_image_io_emscripten import __version__ as test_package_version + +@pytest.fixture +def package_wheel(): + return f"itkwasm_image_io_emscripten-{test_package_version}-py3-none-any.whl" + +@run_in_pyodide(packages=['micropip']) +async def test_example(selenium, package_wheel): + import micropip + await micropip.install(package_wheel) + + # Write your test code here diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py index 493f7415d..6a9beea82 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py @@ -1 +1 @@ -__version__ = "0.3.0" +__version__ = "0.4.0" diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py index 17e7f4ccc..b812d5c04 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/read_image.py @@ -31,7 +31,6 @@ def read_image( :return: Output image :rtype: Image """ - file_name = Path(serialized_image).name extension = ''.join(Path(serialized_image).suffixes) io = None diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py index 493f7415d..6a9beea82 100644 --- a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py @@ -1 +1 @@ -__version__ = "0.3.0" +__version__ = "0.4.0" diff --git a/packages/image-io/typescript/README.md b/packages/image-io/typescript/README.md index d29d798c8..4b88171c0 100644 --- a/packages/image-io/typescript/README.md +++ b/packages/image-io/typescript/README.md @@ -31,7 +31,7 @@ import { ```ts async function readImage( - webWorker: null | Worker, + webWorker: null | Worker | boolean, serializedImage: File | BinaryFile, options: ReadImageOptions = {} ) : Promise @@ -39,7 +39,7 @@ async function readImage( | Parameter | Type | Description | | :---------------: | :-----------------: | :---------------------------------------- | -| `webWorker` | *null or Worker* | WebWorker to use for computation. Set to null to create a new worker. Or, pass an existing worker. | +| `webWorker` | *null or Worker or boolean* | WebWorker to use for computation. Set to null to create a new worker. Or, pass an existing worker. Or, set to `false` to run in the current thread / worker. | | `serializedImage` | *File or BinaryFile* | Input image serialized in the file format. | **`ReadImageOptions` interface:** diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json index b9bb968cc..19a893c84 100644 --- a/packages/image-io/typescript/package.json +++ b/packages/image-io/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@itk-wasm/image-io", - "version": "0.3.0", + "version": "0.4.0", "description": "Input and output for scientific and medical image file formats.", "type": "module", "module": "./dist/index.js", From eca5bda7299f94089627919a5ca5210ea8533730 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Sat, 4 Nov 2023 20:06:36 -0400 Subject: [PATCH 17/23] test(image-io): add python emscripten tests And add additional support: embedded, minified JS module with worker. Missing read_image_async, etc. functions. --- .gitignore | 1 + .../typescript/build/vite.config.js | 2 +- .../test/__init__.py | 0 .../compress-stringify/typescript/README.md | 20 - .../typescript/build/rollup.browser.config.js | 51 - .../typescript/build/rollup.node.config.js | 32 - .../typescript/build/vite.config.js | 3 + .../typescript/package.json | 32 +- .../typescript/pnpm-lock.yaml | 3002 +++++++++ .../typescript/src/index-worker-embedded.ts | 9 + .../typescript/src/index.ts | 1 + .../typescript/src/package.json | 1 + .../typescript/src/pipeline-worker-url.ts | 4 +- .../typescript/src/pipelines-base-url.ts | 2 +- .../test/node/compress-stringify-test.js | 2 +- .../typescript/tsconfig.json | 8 +- .../itkwasm_image_io_emscripten/__init__.py | 46 +- .../bio_rad_read_image_async.py | 60 + .../bio_rad_write_image_async.py | 67 + .../bmp_read_image_async.py | 60 + .../bmp_write_image_async.py | 67 + .../extension_to_image_io.py | 56 + .../fdf_read_image_async.py | 60 + .../fdf_write_image_async.py | 67 + .../gdcm_read_image_async.py | 60 + .../gdcm_write_image_async.py | 67 + .../ge4_read_image_async.py | 60 + .../ge4_write_image_async.py | 67 + .../ge5_read_image_async.py | 60 + .../ge5_write_image_async.py | 67 + .../ge_adw_read_image_async.py | 60 + .../ge_adw_write_image_async.py | 67 + .../gipl_read_image_async.py | 60 + .../gipl_write_image_async.py | 67 + .../image_io_index.py | 25 + .../jpeg_read_image_async.py | 60 + .../jpeg_write_image_async.py | 67 + .../itkwasm_image_io_emscripten/js_package.py | 5885 +---------------- .../lsm_read_image_async.py | 60 + .../lsm_write_image_async.py | 67 + .../meta_read_image_async.py | 60 + .../meta_write_image_async.py | 67 + .../mgh_read_image_async.py | 60 + .../mgh_write_image_async.py | 67 + .../mrc_read_image_async.py | 60 + .../mrc_write_image_async.py | 67 + .../nifti_read_image_async.py | 60 + .../nifti_write_image_async.py | 67 + .../nrrd_read_image_async.py | 60 + .../nrrd_write_image_async.py | 67 + .../png_read_image_async.py | 60 + .../png_write_image_async.py | 67 + .../read_image_async.py | 106 + .../scanco_read_image_async.py | 60 + .../scanco_write_image_async.py | 67 + .../tiff_read_image_async.py | 60 + .../tiff_write_image_async.py | 67 + .../vtk_read_image_async.py | 60 + .../vtk_write_image_async.py | 67 + .../wasm_read_image_async.py | 60 + .../wasm_write_image_async.py | 67 + .../wasm_zstd_read_image_async.py | 60 + .../wasm_zstd_write_image_async.py | 67 + .../write_image_async.py | 95 + .../pyproject.toml | 2 +- .../test/fixtures.py | 29 + .../test/test_bio_rad_async.py | 57 + .../test/test_metaimage_async.py | 65 + .../test/test_read_write_image_async.py | 53 + .../itkwasm_image_io_wasi/image_io_index.py | 6 +- .../typescript/build/rollup.browser.config.js | 49 - .../typescript/build/rollup.node.config.js | 36 - .../build/vite-rollup-watch.config.js | 23 + .../image-io/typescript/build/vite.config.js | 3 + packages/image-io/typescript/package.json | 12 +- packages/image-io/typescript/pnpm-lock.yaml | 3039 +++++++++ .../src/index-worker-embedded.min.ts | 5 + .../typescript/src/index-worker-embedded.ts | 2 +- .../emscripten/emscripten-pyodide-module.js | 7 +- .../python/resources/template.pyproject.toml | 3 +- .../resources/index-worker-embedded.min.ts | 7 + .../resources/index-worker-embedded.ts | 7 + .../resources/template.package.json | 19 +- .../typescript/resources/vite.config.js | 4 +- src/bindgen/typescript/typescript-bindings.js | 1 + src/bindgen/typescript/write-support-files.js | 12 + 86 files changed, 9360 insertions(+), 6131 deletions(-) create mode 100644 packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/test/__init__.py delete mode 100644 packages/compress-stringify/typescript/build/rollup.browser.config.js delete mode 100644 packages/compress-stringify/typescript/build/rollup.node.config.js create mode 100644 packages/compress-stringify/typescript/pnpm-lock.yaml create mode 100644 packages/compress-stringify/typescript/src/index-worker-embedded.ts create mode 120000 packages/compress-stringify/typescript/src/package.json create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/extension_to_image_io.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/image_io_index.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/test/test_bio_rad_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/test/test_metaimage_async.py create mode 100644 packages/image-io/python/itkwasm-image-io-emscripten/test/test_read_write_image_async.py delete mode 100644 packages/image-io/typescript/build/rollup.browser.config.js delete mode 100644 packages/image-io/typescript/build/rollup.node.config.js create mode 100644 packages/image-io/typescript/build/vite-rollup-watch.config.js create mode 100644 packages/image-io/typescript/pnpm-lock.yaml create mode 100644 packages/image-io/typescript/src/index-worker-embedded.min.ts create mode 100644 src/bindgen/typescript/resources/index-worker-embedded.min.ts create mode 100644 src/bindgen/typescript/resources/index-worker-embedded.ts diff --git a/.gitignore b/.gitignore index 258313422..9d15384a1 100644 --- a/.gitignore +++ b/.gitignore @@ -80,6 +80,7 @@ test/pipelines/bindgen-interface-types-pipeline/wasi-build/ test/pipelines/bindgen-interface-types-pipeline/python-web-demo/ packages/image-io/test/ +packages/image-io/typescript/demo-app-rollup/ cypress/screenshots/ cypress/videos/ diff --git a/packages/compare-images/typescript/build/vite.config.js b/packages/compare-images/typescript/build/vite.config.js index 38df171ce..adf8b9cce 100644 --- a/packages/compare-images/typescript/build/vite.config.js +++ b/packages/compare-images/typescript/build/vite.config.js @@ -19,7 +19,7 @@ export default defineConfig({ viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm.zst}', dest: 'pipelines' }, + { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm,wasm.zst}', dest: 'pipelines' }, ], }) ], diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/test/__init__.py b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/test/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/packages/compress-stringify/typescript/README.md b/packages/compress-stringify/typescript/README.md index 4ecb0202c..5bf4ea1ea 100644 --- a/packages/compress-stringify/typescript/README.md +++ b/packages/compress-stringify/typescript/README.md @@ -26,8 +26,6 @@ import { parseStringDecompress, setPipelinesBaseUrl, getPipelinesBaseUrl, - setPipelineWorkerUrl, - getPipelineWorkerUrl, } from "@itk-wasm/compress-stringify" ``` @@ -111,24 +109,6 @@ function setPipelinesBaseUrl( function getPipelinesBaseUrl() : string | URL ``` -#### setPipelineWorkerUrl - -*Set base URL for the itk-wasm pipeline worker script when vendored.* - -```ts -function setPipelineWorkerUrl( - baseUrl: string | URL -) : void -``` - -#### getPipelineWorkerUrl - -*Get base URL for the itk-wasm pipeline worker script when vendored.* - -```ts -function getPipelineWorkerUrl() : string | URL -``` - ### Node interface Import: diff --git a/packages/compress-stringify/typescript/build/rollup.browser.config.js b/packages/compress-stringify/typescript/build/rollup.browser.config.js deleted file mode 100644 index ac03845a3..000000000 --- a/packages/compress-stringify/typescript/build/rollup.browser.config.js +++ /dev/null @@ -1,51 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import copy from 'rollup-plugin-copy' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import nodePolyfills from 'rollup-plugin-polyfill-node' -import ignore from 'rollup-plugin-ignore' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import json from '@rollup/plugin-json' -import path from 'path' - -const itkConfig = './src/itkConfig.js' -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index.ts', - output: [ - { - file: `./dist/bundles/${bundleName}.js`, - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - plugins: [ - copy({ - targets: [ - { src: 'node_modules/itk-wasm/dist/web-workers/bundles/pipeline.worker.js', dest: 'dist/web-workers/' }, - ], - hook: 'writeBundle' - }), - ignore(['crypto']), - nodeResolve({ - preferBuiltins: false, - browser: true, - }), - commonjs({ - transformMixedEsModules: true - }), - nodePolyfills(), - typescript(), - json(), - ], - resolve: { - // where itk-wasm code has 'import ../itkConfig.js` point to the path of itkConfig - alias: { - '../itkConfig.js': itkConfig, - '../../itkConfig.js': itkConfig - } - } -} diff --git a/packages/compress-stringify/typescript/build/rollup.node.config.js b/packages/compress-stringify/typescript/build/rollup.node.config.js deleted file mode 100644 index 8b0695e18..000000000 --- a/packages/compress-stringify/typescript/build/rollup.node.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import path from 'path' - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index-node.ts', - output: [ - { - file: `./dist/bundles/${bundleName}-node.js`, - format: 'es', - sourcemap: true, - plugins: [terser(),], - }, - ], - plugins: [ - commonjs({ - transformMixedEsModules: true - }), - nodeResolve({ - preferBuiltins: true, - browser: false, - }), - typescript(), - json(), - ], -} diff --git a/packages/compress-stringify/typescript/build/vite.config.js b/packages/compress-stringify/typescript/build/vite.config.js index 222e14626..cbaa2e3c0 100644 --- a/packages/compress-stringify/typescript/build/vite.config.js +++ b/packages/compress-stringify/typescript/build/vite.config.js @@ -8,6 +8,9 @@ export default defineConfig({ outDir: '../../../demo-app', emptyOutDir: true, }, + optimizeDeps: { + exclude: ['itk-wasm'] + }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory viteStaticCopy({ diff --git a/packages/compress-stringify/typescript/package.json b/packages/compress-stringify/typescript/package.json index 22e395829..0cc9ad9ed 100644 --- a/packages/compress-stringify/typescript/package.json +++ b/packages/compress-stringify/typescript/package.json @@ -3,14 +3,14 @@ "version": "1.0.0", "description": "Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.", "type": "module", - "module": "./dist/bundles/compress-stringify.js", - "types": "./dist/src/index.d.ts", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { - "types": "./dist/src/index.d.ts", - "browser": "./dist/bundles/compress-stringify.js", - "node": "./dist/bundles/compress-stringify-node.js", - "default": "./dist/bundles/compress-stringify.js" + "types": "./dist/index.d.ts", + "browser": "./dist/index.js", + "node": "./dist/index-node.js", + "default": "./dist/index.js" } }, "scripts": { @@ -25,9 +25,9 @@ "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", - "build:node": "rollup -c ./build/rollup.node.config.js", - "build:browser": "rollup -c ./build/rollup.browser.config.js", + "build": "npm run build:tsc && npm run build:browser:webWorkers && npm run build:browser:workerEmbedded && npm run build:demo", + "build:browser:webWorkers": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/compress-stringify-worker-embedded.js ./src/index-worker-embedded.ts", "build:tsc": "tsc --pretty", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" }, @@ -39,26 +39,16 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.149" + "itk-wasm": "^1.0.0-b.152" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.0", - "@rollup/plugin-typescript": "^11.1.1", "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", "ava": "^5.1.0", "cypress": "^13.3.1", - "rollup": "^3.9.0", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-ignore": "^1.0.10", - "rollup-plugin-polyfill-node": "^0.12.0", + "esbuild": "^0.19.5", "shx": "^0.3.4", "start-server-and-test": "^2.0.0", - "supports-color": "^9.3.1", - "tslib": "^2.5.2", "typescript": "^5.0.4", "vite": "^4.4.11", "vite-plugin-static-copy": "^0.17.0" diff --git a/packages/compress-stringify/typescript/pnpm-lock.yaml b/packages/compress-stringify/typescript/pnpm-lock.yaml new file mode 100644 index 000000000..8ab8d1f5f --- /dev/null +++ b/packages/compress-stringify/typescript/pnpm-lock.yaml @@ -0,0 +1,3002 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + itk-wasm: + specifier: ^1.0.0-b.152 + version: 1.0.0-b.152 + +devDependencies: + '@shoelace-style/shoelace': + specifier: ^2.5.2 + version: 2.11.2(@types/react@18.2.34) + '@types/node': + specifier: ^20.2.5 + version: 20.8.10 + ava: + specifier: ^5.1.0 + version: 5.3.1 + cypress: + specifier: ^13.3.1 + version: 13.4.0 + esbuild: + specifier: ^0.19.5 + version: 0.19.5 + shx: + specifier: ^0.3.4 + version: 0.3.4 + start-server-and-test: + specifier: ^2.0.0 + version: 2.0.1 + typescript: + specifier: ^5.0.4 + version: 5.2.2 + vite: + specifier: ^4.4.11 + version: 4.5.0(@types/node@20.8.10) + vite-plugin-static-copy: + specifier: ^0.17.0 + version: 0.17.0(vite@4.5.0) + +packages: + + /@babel/runtime@7.23.2: + resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + dev: false + + /@colors/colors@1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@ctrl/tinycolor@4.0.2: + resolution: {integrity: sha512-fKQinXE9pJ83J1n+C3rDl2xNLJwfoYNvXLRy5cYZA9hBJJw2q+sbb/AOSNKmLxnTWyNTmy4994dueSwP4opi5g==} + engines: {node: '>=14'} + dev: true + + /@cypress/request@3.0.1: + resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==} + engines: {node: '>= 6'} + dependencies: + aws-sign2: 0.7.0 + aws4: 1.12.0 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + http-signature: 1.3.6 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + performance-now: 2.1.0 + qs: 6.10.4 + safe-buffer: 5.2.1 + tough-cookie: 4.1.3 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + dev: true + + /@cypress/xvfb@1.2.4(supports-color@8.1.1): + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + dependencies: + debug: 3.2.7(supports-color@8.1.1) + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.5: + resolution: {integrity: sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.5: + resolution: {integrity: sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.5: + resolution: {integrity: sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.5: + resolution: {integrity: sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.5: + resolution: {integrity: sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.5: + resolution: {integrity: sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.5: + resolution: {integrity: sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.5: + resolution: {integrity: sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.5: + resolution: {integrity: sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.5: + resolution: {integrity: sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.5: + resolution: {integrity: sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.5: + resolution: {integrity: sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.5: + resolution: {integrity: sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.5: + resolution: {integrity: sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.5: + resolution: {integrity: sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.5: + resolution: {integrity: sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.5: + resolution: {integrity: sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.5: + resolution: {integrity: sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.5: + resolution: {integrity: sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.5: + resolution: {integrity: sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.5: + resolution: {integrity: sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.5: + resolution: {integrity: sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@floating-ui/core@1.5.0: + resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} + dependencies: + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/dom@1.5.3: + resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} + dependencies: + '@floating-ui/core': 1.5.0 + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/utils@0.1.6: + resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + dev: true + + /@hapi/hoek@9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: true + + /@hapi/topo@5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@lit-labs/ssr-dom-shim@1.1.2: + resolution: {integrity: sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==} + dev: true + + /@lit/react@1.0.1(@types/react@18.2.34): + resolution: {integrity: sha512-io4yIAl9ZFY5coI2ix+nSly4rmEKLFyZM66mxOr9xvxDqwtjdVU/g6Tchb7bo+A23+5Uu/1RZpLCpvHLCGi0rw==} + peerDependencies: + '@types/react': 17 || 18 + dependencies: + '@types/react': 18.2.34 + dev: true + + /@lit/reactive-element@2.0.1: + resolution: {integrity: sha512-eu50SQXHRthFwWJMp0oAFg95Rvm6MTPjxSXWuvAu7It90WVFLFpNBoIno7XOXSDvVgTrtKnUV4OLJqys2Svn4g==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.1.2 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@shoelace-style/animations@1.1.0: + resolution: {integrity: sha512-Be+cahtZyI2dPKRm8EZSx3YJQ+jLvEcn3xzRP7tM4tqBnvd/eW/64Xh0iOf0t2w5P8iJKfdBbpVNE9naCaOf2g==} + dev: true + + /@shoelace-style/localize@3.1.2: + resolution: {integrity: sha512-Hf45HeO+vdQblabpyZOTxJ4ZeZsmIUYXXPmoYrrR4OJ5OKxL+bhMz5mK8JXgl7HsoEowfz7+e248UGi861de9Q==} + dev: true + + /@shoelace-style/shoelace@2.11.2(@types/react@18.2.34): + resolution: {integrity: sha512-V94PTZ3CKcRH7NozDIEK5gMG3yeCZhF/3jCpKZ7Wexpf9kOqIRaMGoW3omq21I8NRefNLEknkV9Q392JIZLjBA==} + engines: {node: '>=14.17.0'} + dependencies: + '@ctrl/tinycolor': 4.0.2 + '@floating-ui/dom': 1.5.3 + '@lit/react': 1.0.1(@types/react@18.2.34) + '@shoelace-style/animations': 1.1.0 + '@shoelace-style/localize': 3.1.2 + composed-offset-position: 0.0.4 + lit: 3.0.2 + qr-creator: 1.0.0 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@sideway/address@4.1.4: + resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@sideway/formula@3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: true + + /@sideway/pinpoint@2.0.0: + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + dev: true + + /@thewtex/zstddec@0.2.0: + resolution: {integrity: sha512-lIS+smrfa48WGlDVQSQSm0jBnwVp5XmfGJWU9q0J0fRFY9ohzK4s27Zg2SFMb1NWMp9RiANAdK+/q86EBGWR1Q==} + dev: false + + /@types/emscripten@1.39.9: + resolution: {integrity: sha512-ILdWj4XYtNOqxJaW22NEQx2gJsLfV5ncxYhhGX1a1H1lXl2Ta0gUz7QOnOoF1xQbJwWDjImi8gXN9mKdIf6n9g==} + dev: false + + /@types/node@18.18.8: + resolution: {integrity: sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/node@20.8.10: + resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/prop-types@15.7.9: + resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==} + dev: true + + /@types/react@18.2.34: + resolution: {integrity: sha512-U6eW/alrRk37FU/MS2RYMjx0Va2JGIVXELTODaTIYgvWGCV4Y4TfTUzG8DdmpDNIT0Xpj/R7GfyHOJJrDttcvg==} + dependencies: + '@types/prop-types': 15.7.9 + '@types/scheduler': 0.16.5 + csstype: 3.1.2 + dev: true + + /@types/scheduler@0.16.5: + resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==} + dev: true + + /@types/sinonjs__fake-timers@8.1.1: + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + dev: true + + /@types/sizzle@2.3.5: + resolution: {integrity: sha512-tAe4Q+OLFOA/AMD+0lq8ovp8t3ysxAOeaScnfNdZpUxaGl51ZMDEITxkvFl1STudQ58mz6gzVGl9VhMKhwRnZQ==} + dev: true + + /@types/trusted-types@2.0.5: + resolution: {integrity: sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA==} + dev: true + + /@types/yauzl@2.10.2: + resolution: {integrity: sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==} + requiresBuild: true + dependencies: + '@types/node': 20.8.10 + dev: true + optional: true + + /acorn-walk@8.3.0: + resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + dev: true + + /arrgv@1.0.2: + resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} + engines: {node: '>=8.0.0'} + dev: true + + /arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + dev: true + + /asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + dev: true + + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + /at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /ava@5.3.1: + resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + hasBin: true + peerDependencies: + '@ava/typescript': '*' + peerDependenciesMeta: + '@ava/typescript': + optional: true + dependencies: + acorn: 8.11.2 + acorn-walk: 8.3.0 + ansi-styles: 6.2.1 + arrgv: 1.0.2 + arrify: 3.0.0 + callsites: 4.1.0 + cbor: 8.1.0 + chalk: 5.3.0 + chokidar: 3.5.3 + chunkd: 2.0.1 + ci-info: 3.9.0 + ci-parallel-vars: 1.0.1 + clean-yaml-object: 0.1.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + common-path-prefix: 3.0.0 + concordance: 5.0.4 + currently-unhandled: 0.4.1 + debug: 4.3.4(supports-color@8.1.1) + emittery: 1.0.1 + figures: 5.0.0 + globby: 13.2.2 + ignore-by-default: 2.1.0 + indent-string: 5.0.0 + is-error: 2.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + matcher: 5.0.0 + mem: 9.0.2 + ms: 2.1.3 + p-event: 5.0.1 + p-map: 5.5.0 + picomatch: 2.3.1 + pkg-conf: 4.0.0 + plur: 5.1.0 + pretty-ms: 8.0.0 + resolve-cwd: 3.0.0 + stack-utils: 2.0.6 + strip-ansi: 7.1.0 + supertap: 3.0.1 + temp-dir: 3.0.0 + write-file-atomic: 5.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + dev: true + + /aws4@1.12.0: + resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} + dev: true + + /axios@0.27.2(debug@4.3.4): + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: true + + /axios@1.6.0: + resolution: {integrity: sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==} + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + dependencies: + tweetnacl: 0.14.5 + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /blob-util@2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + dev: true + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: false + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /cachedir@2.4.0: + resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} + engines: {node: '>=6'} + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + + /callsites@4.1.0: + resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} + engines: {node: '>=12.20'} + dev: true + + /caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + dev: true + + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /check-more-types@2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /chunkd@2.0.1: + resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} + dev: true + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /ci-parallel-vars@1.0.1: + resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + dev: true + + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /clean-yaml-object@0.1.0: + resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} + engines: {node: '>=0.10.0'} + dev: true + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + dev: true + + /cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + dev: true + + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + + /commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + dev: true + + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: false + + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + + /common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + + /composed-offset-position@0.0.4: + resolution: {integrity: sha512-vMlvu1RuNegVE0YsCDSV/X4X10j56mq7PCIyOKK74FxkXzGLwhOUmdkJLSdOBOMwWycobGUMgft2lp+YgTe8hw==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.3.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.5.4 + well-known-symbols: 2.0.0 + dev: true + + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true + + /currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + dependencies: + array-find-index: 1.0.2 + dev: true + + /cypress@13.4.0: + resolution: {integrity: sha512-KeWNC9xSHG/ewZURVbaQsBQg2mOKw4XhjJZFKjWbEjgZCdxpPXLpJnfq5Jns1Gvnjp6AlnIfpZfWFlDgVKXdWQ==} + engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} + hasBin: true + requiresBuild: true + dependencies: + '@cypress/request': 3.0.1 + '@cypress/xvfb': 1.2.4(supports-color@8.1.1) + '@types/node': 18.18.8 + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.5 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.4.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.3 + commander: 6.2.1 + common-tags: 1.8.2 + dayjs: 1.11.10 + debug: 4.3.4(supports-color@8.1.1) + enquirer: 2.4.1 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1(supports-color@8.1.1) + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0(enquirer@2.4.1) + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.8 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + process: 0.11.10 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.5.4 + supports-color: 8.1.1 + tmp: 0.2.1 + untildify: 4.0.0 + yauzl: 2.10.0 + dev: true + + /dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + dev: true + + /date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + dependencies: + time-zone: 1.0.0 + dev: true + + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: true + + /debug@3.2.7(supports-color@8.1.1): + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + dev: true + + /debug@4.3.4(supports-color@8.1.1): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + dev: true + + /emittery@1.0.1: + resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} + engines: {node: '>=14.16'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /esbuild@0.19.5: + resolution: {integrity: sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.5 + '@esbuild/android-arm64': 0.19.5 + '@esbuild/android-x64': 0.19.5 + '@esbuild/darwin-arm64': 0.19.5 + '@esbuild/darwin-x64': 0.19.5 + '@esbuild/freebsd-arm64': 0.19.5 + '@esbuild/freebsd-x64': 0.19.5 + '@esbuild/linux-arm': 0.19.5 + '@esbuild/linux-arm64': 0.19.5 + '@esbuild/linux-ia32': 0.19.5 + '@esbuild/linux-loong64': 0.19.5 + '@esbuild/linux-mips64el': 0.19.5 + '@esbuild/linux-ppc64': 0.19.5 + '@esbuild/linux-riscv64': 0.19.5 + '@esbuild/linux-s390x': 0.19.5 + '@esbuild/linux-x64': 0.19.5 + '@esbuild/netbsd-x64': 0.19.5 + '@esbuild/openbsd-x64': 0.19.5 + '@esbuild/sunos-x64': 0.19.5 + '@esbuild/win32-arm64': 0.19.5 + '@esbuild/win32-ia32': 0.19.5 + '@esbuild/win32-x64': 0.19.5 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: true + + /eventemitter2@6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + dev: true + + /execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /executable@4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + dependencies: + pify: 2.3.0 + dev: true + + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: true + + /extract-zip@2.0.1(supports-color@8.1.1): + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.2 + transitivePeerDependencies: + - supports-color + dev: true + + /extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: true + + /figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + dev: true + + /follow-redirects@1.15.3(debug@4.3.4): + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + + /forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + dev: true + + /form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: true + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: false + + /fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /getos@3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + dependencies: + async: 3.2.5 + dev: true + + /getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + dependencies: + assert-plus: 1.0.0 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: false + + /global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + + /globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.1 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /http-signature@1.3.6: + resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.18.0 + dev: true + + /human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /ignore-by-default@2.1.0: + resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} + engines: {node: '>=10 <11 || >=12 <13 || >=14'} + dev: true + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + + /interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: true + + /irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.9.0 + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-error@2.2.2: + resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: true + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + dev: true + + /itk-wasm@1.0.0-b.152: + resolution: {integrity: sha512-AtOy2iLY/lK9s4rzyeB4l9awJKZSFcQjlyfRcl+33DHcuvRDnpvGR2cgD/KEfiXa/7bZh7rg7+NPca4NgYpZ3g==} + hasBin: true + dependencies: + '@babel/runtime': 7.23.2 + '@thewtex/zstddec': 0.2.0 + '@types/emscripten': 1.39.9 + axios: 1.6.0 + commander: 9.5.0 + fs-extra: 10.1.0 + glob: 8.1.0 + markdown-table: 3.0.3 + mime-types: 2.1.35 + wasm-feature-detect: 1.6.1 + webworker-promise: 0.4.4 + transitivePeerDependencies: + - debug + dev: false + + /joi@17.11.0: + resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: true + + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + dev: true + + /json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: true + + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + /jsprim@2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: true + + /lazy-ass@1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + dev: true + + /listr2@3.14.0(enquirer@2.4.1): + resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} + engines: {node: '>=10.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.20 + enquirer: 2.4.1 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.3.0 + rxjs: 7.8.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + dev: true + + /lit-element@4.0.1: + resolution: {integrity: sha512-OxRMJem4HKZt0320HplLkBPoi4KHiEHoPHKd8Lzf07ZQVAOKIjZ32yPLRKRDEolFU1RgrQBfSHQMoxKZ72V3Kw==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.1.2 + '@lit/reactive-element': 2.0.1 + lit-html: 3.0.2 + dev: true + + /lit-html@3.0.2: + resolution: {integrity: sha512-Q1A5lHza3bnmxoWJn6yS6vQZQdExl4fghk8W1G+jnAEdoFNYo5oeBBb/Ol7zSEdKd3TR7+r0zsJQyuWEVguiyQ==} + dependencies: + '@types/trusted-types': 2.0.5 + dev: true + + /lit@3.0.2: + resolution: {integrity: sha512-ZoVUPGgXOQocP4OvxehEOBmC4rWB4cRYDPaz7aFmH8DFytsCi/NeACbr4C6vNPGDEC07BrhUos7uVNayDKLQ2Q==} + dependencies: + '@lit/reactive-element': 2.0.1 + lit-element: 4.0.1 + lit-html: 3.0.2 + dev: true + + /load-json-file@7.0.1: + resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + dependencies: + p-defer: 1.0.0 + dev: true + + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: true + + /markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + dev: false + + /matcher@5.0.0: + resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + dependencies: + blueimp-md5: 2.19.0 + dev: true + + /mem@9.0.2: + resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} + engines: {node: '>=12.20'} + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 4.0.0 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /ospath@1.2.2: + resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + dev: true + + /p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + dev: true + + /p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-timeout: 5.1.0 + dev: true + + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + dependencies: + aggregate-error: 4.0.1 + dev: true + + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + dev: true + + /parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + dev: true + + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: true + + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: true + + /performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pkg-conf@4.0.0: + resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + find-up: 6.3.0 + load-json-file: 7.0.1 + dev: true + + /plur@5.1.0: + resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + irregular-plurals: 3.5.0 + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + dev: true + + /pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + dependencies: + parse-ms: 3.0.0 + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /proxy-from-env@1.0.0: + resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + dev: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + + /ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: true + + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /qr-creator@1.0.0: + resolution: {integrity: sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==} + dev: true + + /qs@6.10.4: + resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.22.8 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + dev: false + + /request-progress@3.0.0: + resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} + dependencies: + throttleit: 1.0.0 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.6.2 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + dependencies: + type-fest: 0.13.1 + dev: true + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + dev: true + + /shx@0.3.4: + resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.8 + shelljs: 0.8.5 + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + dev: true + + /slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /start-server-and-test@2.0.1: + resolution: {integrity: sha512-8PFo4DLLLCDMuS51/BEEtE1m9CAXw1LNVtZSS1PzkYQh6Qf9JUwM4huYeSoUumaaoAyuwYBwCa9OsrcpMqcOdQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.3.4(supports-color@8.1.1) + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 7.0.1(debug@4.3.4) + transitivePeerDependencies: + - supports-color + dev: true + + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /supertap@3.0.1: + resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + indent-string: 5.0.0 + js-yaml: 3.14.1 + serialize-error: 7.0.1 + strip-ansi: 7.1.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + + /throttleit@1.0.0: + resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + dev: true + + /tmp@0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + dev: true + + /type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: true + + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + + /verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + dev: true + + /vite-plugin-static-copy@0.17.0(vite@4.5.0): + resolution: {integrity: sha512-2HpNbHfDt8SDy393AGXh9llHkc8FJMQkI8s3T5WsH3SWLMO+f5cFIyPErl4yGKU9Uh3Vaqsd4lHZYTf042fQ2A==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 + dependencies: + chokidar: 3.5.3 + fast-glob: 3.3.1 + fs-extra: 11.1.1 + picocolors: 1.0.0 + vite: 4.5.0(@types/node@20.8.10) + dev: true + + /vite@4.5.0(@types/node@20.8.10): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.8.10 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /wait-on@7.0.1(debug@4.3.4): + resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + axios: 0.27.2(debug@4.3.4) + joi: 17.11.0 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.1 + transitivePeerDependencies: + - debug + dev: true + + /wasm-feature-detect@1.6.1: + resolution: {integrity: sha512-R1i9ED8UlLu/foILNB1ck9XS63vdtqU/tP1MCugVekETp/ySCrBZRk5I/zI67cI1wlQYeSonNm1PLjDHZDNg6g==} + dev: false + + /webworker-promise@0.4.4: + resolution: {integrity: sha512-NfdSlaWqd+0iSrQudB0N0MELfJ9TVTlynhXMpi06piuZhyc9Yy7Hz6BFu2HUkvIb9lCS0pFW42ptd/JnXVnptg==} + dev: false + + /well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: true + + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true diff --git a/packages/compress-stringify/typescript/src/index-worker-embedded.ts b/packages/compress-stringify/typescript/src/index-worker-embedded.ts new file mode 100644 index 000000000..cdbc5d63d --- /dev/null +++ b/packages/compress-stringify/typescript/src/index-worker-embedded.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' \ No newline at end of file diff --git a/packages/compress-stringify/typescript/src/index.ts b/packages/compress-stringify/typescript/src/index.ts index ed3454294..8196bc415 100644 --- a/packages/compress-stringify/typescript/src/index.ts +++ b/packages/compress-stringify/typescript/src/index.ts @@ -1,6 +1,7 @@ // Generated file. To retain edits, remove this comment. export * from './pipelines-base-url.js' +export * from './pipeline-worker-url.js' import CompressStringifyResult from './compress-stringify-result.js' diff --git a/packages/compress-stringify/typescript/src/package.json b/packages/compress-stringify/typescript/src/package.json new file mode 120000 index 000000000..4e26811d4 --- /dev/null +++ b/packages/compress-stringify/typescript/src/package.json @@ -0,0 +1 @@ +../package.json \ No newline at end of file diff --git a/packages/compress-stringify/typescript/src/pipeline-worker-url.ts b/packages/compress-stringify/typescript/src/pipeline-worker-url.ts index 2ccecc14b..39118ba4a 100644 --- a/packages/compress-stringify/typescript/src/pipeline-worker-url.ts +++ b/packages/compress-stringify/typescript/src/pipeline-worker-url.ts @@ -1,8 +1,8 @@ import { getPipelineWorkerUrl as itkWasmGetPipelineWorkerUrl } from 'itk-wasm' -import packageJson from '../package.json' let pipelineWorkerUrl: string | URL | null | undefined -const defaultPipelineWorkerUrl = `https://cdn.jsdelivr.net/npm/@itk-wasm/compress-stringify@${packageJson.version}/dist/web-workers/pipeline.worker.js` +// Use the version shipped with an app's bundler +const defaultPipelineWorkerUrl = null export function setPipelineWorkerUrl (workerUrl: string | URL | null): void { pipelineWorkerUrl = workerUrl diff --git a/packages/compress-stringify/typescript/src/pipelines-base-url.ts b/packages/compress-stringify/typescript/src/pipelines-base-url.ts index 11dfe9f90..9bedc9678 100644 --- a/packages/compress-stringify/typescript/src/pipelines-base-url.ts +++ b/packages/compress-stringify/typescript/src/pipelines-base-url.ts @@ -1,5 +1,5 @@ import { getPipelinesBaseUrl as itkWasmGetPipelinesBaseUrl } from 'itk-wasm' -import packageJson from '../package.json' +import packageJson from './package.json' let pipelinesBaseUrl: string | URL | undefined let defaultPipelinesBaseUrl: string | URL = `https://cdn.jsdelivr.net/npm/@itk-wasm/compress-stringify@${packageJson.version}/dist/pipelines` diff --git a/packages/compress-stringify/typescript/test/node/compress-stringify-test.js b/packages/compress-stringify/typescript/test/node/compress-stringify-test.js index fe210ab3b..12078a3b1 100644 --- a/packages/compress-stringify/typescript/test/node/compress-stringify-test.js +++ b/packages/compress-stringify/typescript/test/node/compress-stringify-test.js @@ -1,6 +1,6 @@ import test from 'ava' -import { compressStringifyNode, parseStringDecompressNode } from '../../dist/bundles/compress-stringify-node.js' +import { compressStringifyNode, parseStringDecompressNode } from '../../dist/index-node.js' test('Decompress returns what was compressed', async t => { const data = new Uint8Array([222, 173, 190, 239]) diff --git a/packages/compress-stringify/typescript/tsconfig.json b/packages/compress-stringify/typescript/tsconfig.json index 4eba4b8ec..242f02a0c 100644 --- a/packages/compress-stringify/typescript/tsconfig.json +++ b/packages/compress-stringify/typescript/tsconfig.json @@ -16,8 +16,10 @@ "noImplicitReturns": true, "skipLibCheck": true, "declaration": true, - "emitDeclarationOnly": true, - "declarationDir": "dist/" + "emitDeclarationOnly": false, + "outDir": "dist/", + "rootDir": "src/" }, - "include": ["src/*.ts"] + "include": ["src/*.ts"], + "exclude": ["src/index-worker-embedded*.ts"] } diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py index 1370b2a2f..ed63eabee 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/__init__.py @@ -1,7 +1,49 @@ -# Generated file. To retain edits, remove this comment. - """itkwasm-image-io-emscripten: Input and output for scientific and medical image file formats. Emscripten implementation.""" +from .read_image_async import read_image_async, imread_async +from .write_image_async import write_image_async, imwrite_async +from .bio_rad_read_image_async import bio_rad_read_image_async +from .bio_rad_write_image_async import bio_rad_write_image_async +from .bmp_read_image_async import bmp_read_image_async +from .bmp_write_image_async import bmp_write_image_async +from .fdf_read_image_async import fdf_read_image_async +from .fdf_write_image_async import fdf_write_image_async +from .gdcm_read_image_async import gdcm_read_image_async +from .gdcm_write_image_async import gdcm_write_image_async +from .ge_adw_read_image_async import ge_adw_read_image_async +from .ge_adw_write_image_async import ge_adw_write_image_async +from .ge4_read_image_async import ge4_read_image_async +from .ge4_write_image_async import ge4_write_image_async +from .ge5_read_image_async import ge5_read_image_async +from .ge5_write_image_async import ge5_write_image_async +from .gipl_read_image_async import gipl_read_image_async +from .gipl_write_image_async import gipl_write_image_async +from .jpeg_read_image_async import jpeg_read_image_async +from .jpeg_write_image_async import jpeg_write_image_async +from .lsm_read_image_async import lsm_read_image_async +from .lsm_write_image_async import lsm_write_image_async +from .meta_read_image_async import meta_read_image_async +from .meta_write_image_async import meta_write_image_async +from .mgh_read_image_async import mgh_read_image_async +from .mgh_write_image_async import mgh_write_image_async +from .mrc_read_image_async import mrc_read_image_async +from .mrc_write_image_async import mrc_write_image_async +from .nifti_read_image_async import nifti_read_image_async +from .nifti_write_image_async import nifti_write_image_async +from .nrrd_read_image_async import nrrd_read_image_async +from .nrrd_write_image_async import nrrd_write_image_async +from .png_read_image_async import png_read_image_async +from .png_write_image_async import png_write_image_async +from .scanco_read_image_async import scanco_read_image_async +from .scanco_write_image_async import scanco_write_image_async +from .tiff_read_image_async import tiff_read_image_async +from .tiff_write_image_async import tiff_write_image_async +from .vtk_read_image_async import vtk_read_image_async +from .vtk_write_image_async import vtk_write_image_async +from .wasm_read_image_async import wasm_read_image_async +from .wasm_write_image_async import wasm_write_image_async +from .wasm_zstd_read_image_async import wasm_zstd_read_image_async +from .wasm_zstd_write_image_async import wasm_zstd_write_image_async from ._version import __version__ diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_read_image_async.py new file mode 100644 index 000000000..6d2756a0a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def bio_rad_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.bioRadReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_write_image_async.py new file mode 100644 index 000000000..a2449cad6 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bio_rad_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def bio_rad_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.bioRadWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_read_image_async.py new file mode 100644 index 000000000..06044a600 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def bmp_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.bmpReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_write_image_async.py new file mode 100644 index 000000000..1911ecaeb --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/bmp_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def bmp_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.bmpWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/extension_to_image_io.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/extension_to_image_io.py new file mode 100644 index 000000000..5f9ab9793 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/extension_to_image_io.py @@ -0,0 +1,56 @@ +from collections import OrderedDict + +extension_to_image_io = OrderedDict([ + ('.bmp', 'bmp'), + + ('.dcm', 'gdcm'), + + ('.gipl', 'gipl'), + ('.gipl.gz', 'gipl'), + + ('.hdf5', 'hdf5'), + + ('.jpg', 'jpeg'), + ('.jpeg', 'jpeg'), + + ('.iwi', 'wasm'), + ('.iwi.cbor', 'wasm'), + ('.iwi.cbor.zst', 'wasmZstd'), + + ('.lsm', 'lsm'), + + ('.mnc', 'mnc'), + ('.mnc.gz', 'mnc'), + ('.mnc2', 'mnc'), + + ('.mgh', 'mgh'), + ('.mgz', 'mgh'), + ('.mgh.gz', 'mgh'), + + ('.mha', 'meta'), + ('.mhd', 'meta'), + + ('.mrc', 'mrc'), + + ('.nia', 'nifti'), + ('.nii', 'nifti'), + ('.nii.gz', 'nifti'), + ('.hdr', 'nifti'), + + ('.nrrd', 'nrrd'), + ('.nhdr', 'nrrd'), + + ('.png', 'png'), + + ('.pic', 'bioRad'), + + ('.tif', 'tiff'), + ('.tiff', 'tiff'), + + ('.vtk', 'vtk'), + + ('.isq', 'scanco'), + ('.aim', 'scanco'), + + ('.fdf', 'fdf'), +]) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_read_image_async.py new file mode 100644 index 000000000..d45ea3df0 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def fdf_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.fdfReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_write_image_async.py new file mode 100644 index 000000000..5ae800929 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/fdf_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def fdf_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.fdfWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_read_image_async.py new file mode 100644 index 000000000..6b4c155e8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def gdcm_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.gdcmReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_write_image_async.py new file mode 100644 index 000000000..56fafca7b --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gdcm_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def gdcm_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.gdcmWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_read_image_async.py new file mode 100644 index 000000000..cb445a581 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def ge4_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.ge4ReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_write_image_async.py new file mode 100644 index 000000000..3d6bc0fbd --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge4_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def ge4_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.ge4WriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_read_image_async.py new file mode 100644 index 000000000..71db0e98e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def ge5_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.ge5ReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_write_image_async.py new file mode 100644 index 000000000..7968a0525 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge5_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def ge5_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.ge5WriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_read_image_async.py new file mode 100644 index 000000000..ed3c188e0 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def ge_adw_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.geAdwReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_write_image_async.py new file mode 100644 index 000000000..68d7502fb --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/ge_adw_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def ge_adw_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.geAdwWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_read_image_async.py new file mode 100644 index 000000000..373154092 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def gipl_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.giplReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_write_image_async.py new file mode 100644 index 000000000..da7ae3843 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/gipl_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def gipl_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.giplWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/image_io_index.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/image_io_index.py new file mode 100644 index 000000000..de339c7c0 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/image_io_index.py @@ -0,0 +1,25 @@ +image_io_index = [ + 'png', + 'meta', + 'tiff', + 'nifti', + 'jpeg', + 'nrrd', + 'vtk', + 'bmp', + 'hdf5', + 'minc', + 'mrc', + 'lsm', + 'mgh', + 'bio_rad', + 'gipl', + 'ge_adw', + 'ge4', + 'ge5', + 'gdcm', + 'scanco', + 'wasm', + 'wasm_zstd', +] + diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_read_image_async.py new file mode 100644 index 000000000..9c7363640 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def jpeg_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.jpegReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_write_image_async.py new file mode 100644 index 000000000..025f3a093 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/jpeg_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def jpeg_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.jpegWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py index a60736934..e9133f954 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py @@ -3,5889 +3,6 @@ from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ -default_js_module = """data:text/javascript;charset=utf-8,var __create = Object.create; -var __defProp = Object.defineProperty; -var __getOwnPropDesc = Object.getOwnPropertyDescriptor; -var __getOwnPropNames = Object.getOwnPropertyNames; -var __getProtoOf = Object.getPrototypeOf; -var __hasOwnProp = Object.prototype.hasOwnProperty; -var __commonJS = (cb, mod) => function __require() { - return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; -}; -var __copyProps = (to, from, except, desc) => { - if (from && typeof from === "object" || typeof from === "function") { - for (let key of __getOwnPropNames(from)) - if (!__hasOwnProp.call(to, key) && key !== except) - __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); - } - return to; -}; -var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( - // If the importer is in node compatibility mode or this is not an ESM - // file that has been converted to a CommonJS file using a Babel- - // compatible transform (i.e. "__esModule" has not been set), then set - // "default" to the CommonJS "module.exports" for node compatibility. - isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, - mod -)); - -// node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/tiny-emitter.js -var require_tiny_emitter = __commonJS({ - "node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/tiny-emitter.js"(exports, module) { - var TinyEmitter = class { - constructor() { - Object.defineProperty(this, "__listeners", { - value: {}, - enumerable: false, - writable: false - }); - } - emit(eventName, ...args) { - if (!this.__listeners[eventName]) - return this; - for (const handler of this.__listeners[eventName]) { - handler(...args); - } - return this; - } - once(eventName, handler) { - const once = (...args) => { - this.off(eventName, once); - handler(...args); - }; - return this.on(eventName, once); - } - on(eventName, handler) { - if (!this.__listeners[eventName]) - this.__listeners[eventName] = []; - this.__listeners[eventName].push(handler); - return this; - } - off(eventName, handler) { - if (handler) - this.__listeners[eventName] = this.__listeners[eventName].filter((h) => h !== handler); - else - this.__listeners[eventName] = []; - return this; - } - }; - module.exports = TinyEmitter; - } -}); - -// node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/index.js -var require_src = __commonJS({ - "node_modules/.pnpm/webworker-promise@0.4.4/node_modules/webworker-promise/src/index.js"(exports, module) { - var TinyEmitter = require_tiny_emitter(); - var MESSAGE_RESULT = 0; - var MESSAGE_EVENT = 1; - var RESULT_SUCCESS = 1; - var Worker2 = class extends TinyEmitter { - /** - * - * @param worker {Worker} - */ - constructor(worker) { - super(); - this._messageId = 1; - this._messages = /* @__PURE__ */ new Map(); - this._worker = worker; - this._worker.onmessage = this._onMessage.bind(this); - this._id = Math.ceil(Math.random() * 1e7); - } - terminate() { - this._worker.terminate(); - } - /** - * return true if there is no unresolved jobs - * @returns {boolean} - */ - isFree() { - return this._messages.size === 0; - } - jobsLength() { - return this._messages.size; - } - /** - * @param operationName string - * @param data any - * @param transferable array - * @param onEvent function - * @returns {Promise} - */ - exec(operationName, data = null, transferable = [], onEvent) { - return new Promise((res, rej) => { - const messageId = this._messageId++; - this._messages.set(messageId, [res, rej, onEvent]); - this._worker.postMessage([messageId, data, operationName], transferable || []); - }); - } - /** - * - * @param data any - * @param transferable array - * @param onEvent function - * @returns {Promise} - */ - postMessage(data = null, transferable = [], onEvent) { - return new Promise((res, rej) => { - const messageId = this._messageId++; - this._messages.set(messageId, [res, rej, onEvent]); - this._worker.postMessage([messageId, data], transferable || []); - }); - } - emit(eventName, ...args) { - this._worker.postMessage({ eventName, args }); - } - _onMessage(e) { - if (!Array.isArray(e.data) && e.data.eventName) { - return super.emit(e.data.eventName, ...e.data.args); - } - const [type, ...args] = e.data; - if (type === MESSAGE_EVENT) - this._onEvent(...args); - else if (type === MESSAGE_RESULT) - this._onResult(...args); - else - throw new Error(`Wrong message type '${type}'`); - } - _onResult(messageId, success, payload) { - const [res, rej] = this._messages.get(messageId); - this._messages.delete(messageId); - return success === RESULT_SUCCESS ? res(payload) : rej(payload); - } - _onEvent(messageId, eventName, data) { - const [, , onEvent] = this._messages.get(messageId); - if (onEvent) { - onEvent(eventName, data); - } - } - }; - module.exports = Worker2; - } -}); - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/version.js -var version = "1.0.0-b.152"; -var version_default = version; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/itkConfig.js -var itkConfig = { - pipelineWorkerUrl: `https://cdn.jsdelivr.net/npm/itk-wasm@${version_default}/dist/core/web-workers/bundles/pipeline.min.worker.js`, - imageIOUrl: `https://cdn.jsdelivr.net/npm/itk-image-io@${version_default}`, - meshIOUrl: `https://cdn.jsdelivr.net/npm/itk-mesh-io@${version_default}`, - pipelinesUrl: `https://cdn.jsdelivr.net/npm/itk-wasm@${version_default}/dist/pipelines` -}; -var itkConfig_default = itkConfig; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/InterfaceTypes.js -var InterfaceTypes = { - // Todo: remove Interface prefix after IOTypes has been removed - TextFile: "InterfaceTextFile", - BinaryFile: "InterfaceBinaryFile", - TextStream: "InterfaceTextStream", - BinaryStream: "InterfaceBinaryStream", - Image: "InterfaceImage", - Mesh: "InterfaceMesh", - PolyData: "InterfacePolyData", - JsonCompatible: "InterfaceJsonCompatible" -}; -var InterfaceTypes_default = InterfaceTypes; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/int-types.js -var IntTypes = { - Int8: "int8", - UInt8: "uint8", - Int16: "int16", - UInt16: "uint16", - Int32: "int32", - UInt32: "uint32", - Int64: "int64", - UInt64: "uint64", - SizeValueType: "uint64", - IdentifierType: "uint64", - IndexValueType: "int64", - OffsetValueType: "int64" -}; -var int_types_default = IntTypes; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/float-types.js -var FloatTypes = { - Float32: "float32", - Float64: "float64", - SpacePrecisionType: "float64" -}; -var float_types_default = FloatTypes; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/IOTypes.js -var IOTypes = { - Text: "Text", - Binary: "Binary", - Image: "Image", - Mesh: "Mesh" -}; -var IOTypes_default = IOTypes; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/pixel-types.js -var PixelTypes = { - Unknown: "Unknown", - Scalar: "Scalar", - RGB: "RGB", - RGBA: "RGBA", - Offset: "Offset", - Vector: "Vector", - Point: "Point", - CovariantVector: "CovariantVector", - SymmetricSecondRankTensor: "SymmetricSecondRankTensor", - DiffusionTensor3D: "DiffusionTensor3D", - Complex: "Complex", - FixedArray: "FixedArray", - Array: "Array", - Matrix: "Matrix", - VariableLengthVector: "VariableLengthVector", - VariableSizeMatrix: "VariableSizeMatrix" -}; -var pixel_types_default = PixelTypes; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/setMatrixElement.js -function setMatrixElement(matrixData, columns, row, column, value) { - matrixData[column + row * columns] = value; -} -var setMatrixElement_default = setMatrixElement; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/image-type.js -var ImageType = class { - constructor(dimension = 2, componentType = int_types_default.UInt8, pixelType = pixel_types_default.Scalar, components = 1) { - this.dimension = dimension; - this.componentType = componentType; - this.pixelType = pixelType; - this.components = components; - } -}; -var image_type_default = ImageType; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/interface-types/image.js -var Image = class { - constructor(imageType = new image_type_default()) { - this.imageType = imageType; - this.name = "image"; - const dimension = imageType.dimension; - this.origin = new Array(dimension); - this.origin.fill(0); - this.spacing = new Array(dimension); - this.spacing.fill(1); - this.direction = new Float64Array(dimension * dimension); - this.direction.fill(0); - for (let ii = 0; ii < dimension; ii++) { - setMatrixElement_default(this.direction, dimension, ii, ii, 1); - } - this.size = new Array(dimension); - this.size.fill(0); - this.metadata = /* @__PURE__ */ new Map(); - this.data = null; - } -}; -var image_default = Image; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/bufferToTypedArray.js -function bufferToTypedArray(wasmType, buffer) { - let typedArray = null; - switch (wasmType) { - case int_types_default.UInt8: { - typedArray = new Uint8Array(buffer); - break; - } - case int_types_default.Int8: { - typedArray = new Int8Array(buffer); - break; - } - case int_types_default.UInt16: { - typedArray = new Uint16Array(buffer); - break; - } - case int_types_default.Int16: { - typedArray = new Int16Array(buffer); - break; - } - case int_types_default.UInt32: { - typedArray = new Uint32Array(buffer); - break; - } - case int_types_default.Int32: { - typedArray = new Int32Array(buffer); - break; - } - case int_types_default.UInt64: { - if (typeof globalThis.BigUint64Array === "function") { - typedArray = new BigUint64Array(buffer); - } else { - typedArray = new Uint8Array(buffer); - } - break; - } - case int_types_default.Int64: { - if (typeof globalThis.BigInt64Array === "function") { - typedArray = new BigInt64Array(buffer); - } else { - typedArray = new Uint8Array(buffer); - } - break; - } - case float_types_default.Float32: { - typedArray = new Float32Array(buffer); - break; - } - case float_types_default.Float64: { - typedArray = new Float64Array(buffer); - break; - } - case "null": { - typedArray = null; - break; - } - case null: { - typedArray = null; - break; - } - default: - throw new Error("Type is not supported as a TypedArray"); - } - return typedArray; -} -var bufferToTypedArray_default = bufferToTypedArray; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/copyImage.js -function copyImage(image) { - const copy = new image_default(image.imageType); - copy.name = image.name; - copy.origin = Array.from(image.origin); - copy.spacing = Array.from(image.spacing); - copy.direction = image.direction.slice(); - copy.size = Array.from(image.size); - if (image.data !== null) { - const CTor = image.data.constructor; - copy.data = new CTor(image.data.length); - if (copy.data != null) { - copy.data.set(image.data, 0); - } - } - return copy; -} -var copyImage_default = copyImage; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/stackImages.js -function stackImages(images) { - if (images.length < 1) { - throw Error("At least one images is required."); - } - const firstImage = images[0]; - if (firstImage.data === null) { - throw Error("Image data is null."); - } - const result = new image_default(firstImage.imageType); - result.origin = Array.from(firstImage.origin); - result.spacing = Array.from(firstImage.spacing); - const dimension = result.imageType.dimension; - result.direction = firstImage.direction.slice(); - const stackOn = dimension - 1; - result.size = Array.from(firstImage.size); - const stackedSize = images.reduce((accumulator, currentValue) => { - return accumulator + currentValue.size[stackOn]; - }, 0); - result.size[stackOn] = stackedSize; - const dataSize = result.size.reduce((accumulator, currentValue) => { - return accumulator * currentValue; - }, 1) * result.imageType.components; - const CTor = firstImage.data.constructor; - result.data = new CTor(dataSize); - let offsetBase = result.imageType.components; - for (let subIndex = 0; subIndex < result.size.length - 1; subIndex++) { - offsetBase *= result.size[subIndex]; - } - let stackIndex = 0; - if (result.data != null) { - for (let index = 0; index < images.length; index++) { - result.data.set(images[index].data, offsetBase * stackIndex); - stackIndex += images[index].size[stackOn]; - } - } else { - throw Error("Could not create result image data."); - } - return result; -} -var stackImages_default = stackImages; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/castImage.js -function castImage(inputImage, options) { - const outputImageType = Object.assign({}, inputImage.imageType); - if (typeof options !== "undefined" && typeof options.pixelType !== "undefined") { - outputImageType.pixelType = options.pixelType; - if (options.pixelType === pixel_types_default.Scalar && outputImageType.components !== 1) { - throw new Error("Cannot cast multi-component image to a scalar image"); - } - } - if (typeof options !== "undefined" && typeof options.componentType !== "undefined" && options.componentType !== inputImage.imageType.componentType) { - outputImageType.componentType = options.componentType; - } - const outputImage = new image_default(outputImageType); - outputImage.name = inputImage.name; - outputImage.origin = Array.from(inputImage.origin); - outputImage.spacing = Array.from(inputImage.spacing); - outputImage.direction = inputImage.direction.slice(); - outputImage.size = Array.from(inputImage.size); - outputImage.metadata = new Map(JSON.parse(JSON.stringify(Array.from(inputImage.metadata)))); - if (inputImage.data !== null) { - if (typeof options !== "undefined" && typeof options.componentType !== "undefined" && options.componentType !== inputImage.imageType.componentType) { - switch (inputImage.imageType.componentType) { - case int_types_default.UInt8: - case int_types_default.Int8: - case int_types_default.UInt16: - case int_types_default.Int16: - case int_types_default.UInt32: - case int_types_default.Int32: - case float_types_default.Float32: - case float_types_default.Float64: - switch (outputImage.imageType.componentType) { - case int_types_default.UInt8: - outputImage.data = new Uint8Array(inputImage.data); - break; - case int_types_default.Int8: - outputImage.data = new Int8Array(inputImage.data); - break; - case int_types_default.UInt16: - outputImage.data = new Uint16Array(inputImage.data); - break; - case int_types_default.Int16: - outputImage.data = new Int16Array(inputImage.data); - break; - case int_types_default.UInt32: - outputImage.data = new Uint32Array(inputImage.data); - break; - case int_types_default.Int32: - outputImage.data = new Int32Array(inputImage.data); - break; - case float_types_default.Float32: - outputImage.data = new Float32Array(inputImage.data); - break; - case float_types_default.Float64: - outputImage.data = new Float64Array(inputImage.data); - break; - case int_types_default.UInt64: - outputImage.data = new BigUint64Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = BigInt.asIntN(64, BigInt(inputImage.data[idx])); - } - break; - case int_types_default.Int64: - outputImage.data = new BigInt64Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = BigInt.asUintN(64, BigInt(inputImage.data[idx])); - } - break; - } - break; - case int_types_default.UInt64: - case int_types_default.Int64: - switch (outputImage.imageType.componentType) { - case int_types_default.UInt8: - outputImage.data = new Uint8Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case int_types_default.Int8: - outputImage.data = new Int8Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case int_types_default.UInt16: - outputImage.data = new Uint16Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case int_types_default.Int16: - outputImage.data = new Int16Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case int_types_default.UInt32: - outputImage.data = new Uint32Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case int_types_default.Int32: - outputImage.data = new Int32Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case float_types_default.Float32: - outputImage.data = new Float32Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case float_types_default.Float64: - outputImage.data = new Float64Array(inputImage.data.length); - for (let idx = 0; idx < outputImage.data.length; idx++) { - outputImage.data[idx] = Number(inputImage.data[idx]); - } - break; - case int_types_default.UInt64: - outputImage.data = new BigUint64Array(inputImage.data); - break; - case int_types_default.Int64: - outputImage.data = new BigInt64Array(inputImage.data); - break; - } - break; - } - } else { - const CTor = inputImage.data.constructor; - outputImage.data = new CTor(inputImage.data.length); - if (outputImage.data != null) { - outputImage.data.set(inputImage.data, 0); - } - } - } - return outputImage; -} -var castImage_default = castImage; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/WorkerPool.js -var __rest = function(s, e) { - var t = {}; - for (var p in s) - if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) - t[p] = s[p]; - if (s != null && typeof Object.getOwnPropertySymbols === "function") - for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { - if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) - t[p[i]] = s[p[i]]; - } - return t; -}; -var WorkerPool = class { - /* poolSize is the maximum number of web workers to create in the pool. - * - * The function, fcn, should accept null or an existing worker as its first argument. - * It most also return and object with the used worker on the `webWorker` - * property. * Example: runPipeline. - * - **/ - constructor(poolSize, fcn) { - this.fcn = fcn; - this.workerQueue = new Array(poolSize); - this.workerQueue.fill(null); - this.runInfo = []; - } - /* - * Run the tasks specified by the arguments in the taskArgsArray that will - * be passed to the pool fcn. - * - * An optional progressCallback will be called with the number of complete - * tasks and the total number of tasks as arguments every time a task has - * completed. - * - * Returns an object containing a promise ('promise') to communicate results - * as well as an id ('runId') which can be used to cancel any remaining pending - * tasks before they complete. - */ - runTasks(taskArgsArray, progressCallback = null) { - const info = { - taskQueue: [], - results: [], - addingTasks: false, - postponed: false, - runningWorkers: 0, - index: 0, - completedTasks: 0, - progressCallback, - canceled: false - }; - this.runInfo.push(info); - info.index = this.runInfo.length - 1; - return { - promise: new Promise((resolve, reject) => { - info.resolve = resolve; - info.reject = reject; - info.results = new Array(taskArgsArray.length); - info.completedTasks = 0; - info.addingTasks = true; - taskArgsArray.forEach((taskArg, index) => { - this.addTask(info.index, index, taskArg); - }); - info.addingTasks = false; - }), - runId: info.index - }; - } - terminateWorkers() { - for (let index = 0; index < this.workerQueue.length; index++) { - const worker = this.workerQueue[index]; - if (worker != null) { - worker.terminate(); - } - this.workerQueue[index] = null; - } - } - cancel(runId) { - const info = this.runInfo[runId]; - if (info !== null && info !== void 0) { - info.canceled = true; - } - } - addTask(infoIndex, resultIndex, taskArgs) { - const info = this.runInfo[infoIndex]; - if ((info === null || info === void 0 ? void 0 : info.canceled) === true) { - info.reject("Remaining tasks canceled"); - this.clearTask(info.index); - return; - } - if (this.workerQueue.length > 0) { - const worker = this.workerQueue.pop(); - info.runningWorkers++; - this.fcn(worker, ...taskArgs).then((_a) => { - var { webWorker } = _a, result = __rest(_a, ["webWorker"]); - this.workerQueue.push(webWorker); - if (this.runInfo[infoIndex] !== null) { - info.runningWorkers--; - info.results[resultIndex] = result; - info.completedTasks++; - if (info.progressCallback != null) { - info.progressCallback(info.completedTasks, info.results.length); - } - if (info.taskQueue.length > 0) { - const reTask = info.taskQueue.shift(); - this.addTask(infoIndex, reTask[0], reTask[1]); - } else if (!info.addingTasks && info.runningWorkers === 0) { - const results = info.results; - info.resolve(results); - this.clearTask(info.index); - } - } - }).catch((error) => { - info.reject(error); - this.clearTask(info.index); - }); - } else { - if (info.runningWorkers !== 0 || info.postponed) { - info.taskQueue.push([resultIndex, taskArgs]); - } else { - info.postponed = true; - setTimeout(() => { - info.postponed = false; - this.addTask(info.index, resultIndex, taskArgs); - }, 50); - } - } - } - clearTask(clearIndex) { - this.runInfo[clearIndex].results = []; - this.runInfo[clearIndex].taskQueue = []; - this.runInfo[clearIndex].progressCallback = null; - this.runInfo[clearIndex].canceled = null; - this.runInfo[clearIndex].reject = () => { - }; - this.runInfo[clearIndex].resolve = () => { - }; - } -}; -var WorkerPool_default = WorkerPool; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/getTransferables.js -var haveSharedArrayBuffer = typeof globalThis.SharedArrayBuffer !== "undefined"; -function getTransferables(data) { - if (data === void 0 || data === null) { - return []; - } - const transferables = []; - for (let i = 0; i < data.length; i++) { - const transferable = getTransferable(data[i]); - if (transferable !== null) { - transferables.push(transferable); - } - } - return transferables; -} -function getTransferable(data) { - if (data === void 0 || data === null) { - return null; - } - let result = null; - if (data.buffer !== void 0) { - result = data.buffer; - } else if (data.byteLength !== void 0) { - result = data; - } - if (haveSharedArrayBuffer && result instanceof SharedArrayBuffer) { - return null; - } - return result; -} -var getTransferables_default = getTransferables; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/bind.js -function bind(fn, thisArg) { - return function wrap() { - return fn.apply(thisArg, arguments); - }; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/utils.js -var { toString } = Object.prototype; -var { getPrototypeOf } = Object; -var kindOf = ((cache) => (thing) => { - const str = toString.call(thing); - return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase()); -})(/* @__PURE__ */ Object.create(null)); -var kindOfTest = (type) => { - type = type.toLowerCase(); - return (thing) => kindOf(thing) === type; -}; -var typeOfTest = (type) => (thing) => typeof thing === type; -var { isArray } = Array; -var isUndefined = typeOfTest("undefined"); -function isBuffer(val) { - return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val); -} -var isArrayBuffer = kindOfTest("ArrayBuffer"); -function isArrayBufferView(val) { - let result; - if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) { - result = ArrayBuffer.isView(val); - } else { - result = val && val.buffer && isArrayBuffer(val.buffer); - } - return result; -} -var isString = typeOfTest("string"); -var isFunction = typeOfTest("function"); -var isNumber = typeOfTest("number"); -var isObject = (thing) => thing !== null && typeof thing === "object"; -var isBoolean = (thing) => thing === true || thing === false; -var isPlainObject = (val) => { - if (kindOf(val) !== "object") { - return false; - } - const prototype3 = getPrototypeOf(val); - return (prototype3 === null || prototype3 === Object.prototype || Object.getPrototypeOf(prototype3) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val); -}; -var isDate = kindOfTest("Date"); -var isFile = kindOfTest("File"); -var isBlob = kindOfTest("Blob"); -var isFileList = kindOfTest("FileList"); -var isStream = (val) => isObject(val) && isFunction(val.pipe); -var isFormData = (thing) => { - let kind; - return thing && (typeof FormData === "function" && thing instanceof FormData || isFunction(thing.append) && ((kind = kindOf(thing)) === "formdata" || // detect form-data instance - kind === "object" && isFunction(thing.toString) && thing.toString() === "[object FormData]")); -}; -var isURLSearchParams = kindOfTest("URLSearchParams"); -var trim = (str) => str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, ""); -function forEach(obj, fn, { allOwnKeys = false } = {}) { - if (obj === null || typeof obj === "undefined") { - return; - } - let i; - let l; - if (typeof obj !== "object") { - obj = [obj]; - } - if (isArray(obj)) { - for (i = 0, l = obj.length; i < l; i++) { - fn.call(null, obj[i], i, obj); - } - } else { - const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj); - const len = keys.length; - let key; - for (i = 0; i < len; i++) { - key = keys[i]; - fn.call(null, obj[key], key, obj); - } - } -} -function findKey(obj, key) { - key = key.toLowerCase(); - const keys = Object.keys(obj); - let i = keys.length; - let _key; - while (i-- > 0) { - _key = keys[i]; - if (key === _key.toLowerCase()) { - return _key; - } - } - return null; -} -var _global = (() => { - if (typeof globalThis !== "undefined") - return globalThis; - return typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : global; -})(); -var isContextDefined = (context) => !isUndefined(context) && context !== _global; -function merge() { - const { caseless } = isContextDefined(this) && this || {}; - const result = {}; - const assignValue = (val, key) => { - const targetKey = caseless && findKey(result, key) || key; - if (isPlainObject(result[targetKey]) && isPlainObject(val)) { - result[targetKey] = merge(result[targetKey], val); - } else if (isPlainObject(val)) { - result[targetKey] = merge({}, val); - } else if (isArray(val)) { - result[targetKey] = val.slice(); - } else { - result[targetKey] = val; - } - }; - for (let i = 0, l = arguments.length; i < l; i++) { - arguments[i] && forEach(arguments[i], assignValue); - } - return result; -} -var extend = (a, b, thisArg, { allOwnKeys } = {}) => { - forEach(b, (val, key) => { - if (thisArg && isFunction(val)) { - a[key] = bind(val, thisArg); - } else { - a[key] = val; - } - }, { allOwnKeys }); - return a; -}; -var stripBOM = (content) => { - if (content.charCodeAt(0) === 65279) { - content = content.slice(1); - } - return content; -}; -var inherits = (constructor, superConstructor, props, descriptors2) => { - constructor.prototype = Object.create(superConstructor.prototype, descriptors2); - constructor.prototype.constructor = constructor; - Object.defineProperty(constructor, "super", { - value: superConstructor.prototype - }); - props && Object.assign(constructor.prototype, props); -}; -var toFlatObject = (sourceObj, destObj, filter2, propFilter) => { - let props; - let i; - let prop; - const merged = {}; - destObj = destObj || {}; - if (sourceObj == null) - return destObj; - do { - props = Object.getOwnPropertyNames(sourceObj); - i = props.length; - while (i-- > 0) { - prop = props[i]; - if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) { - destObj[prop] = sourceObj[prop]; - merged[prop] = true; - } - } - sourceObj = filter2 !== false && getPrototypeOf(sourceObj); - } while (sourceObj && (!filter2 || filter2(sourceObj, destObj)) && sourceObj !== Object.prototype); - return destObj; -}; -var endsWith = (str, searchString, position) => { - str = String(str); - if (position === void 0 || position > str.length) { - position = str.length; - } - position -= searchString.length; - const lastIndex = str.indexOf(searchString, position); - return lastIndex !== -1 && lastIndex === position; -}; -var toArray = (thing) => { - if (!thing) - return null; - if (isArray(thing)) - return thing; - let i = thing.length; - if (!isNumber(i)) - return null; - const arr = new Array(i); - while (i-- > 0) { - arr[i] = thing[i]; - } - return arr; -}; -var isTypedArray = ((TypedArray) => { - return (thing) => { - return TypedArray && thing instanceof TypedArray; - }; -})(typeof Uint8Array !== "undefined" && getPrototypeOf(Uint8Array)); -var forEachEntry = (obj, fn) => { - const generator = obj && obj[Symbol.iterator]; - const iterator = generator.call(obj); - let result; - while ((result = iterator.next()) && !result.done) { - const pair = result.value; - fn.call(obj, pair[0], pair[1]); - } -}; -var matchAll = (regExp, str) => { - let matches; - const arr = []; - while ((matches = regExp.exec(str)) !== null) { - arr.push(matches); - } - return arr; -}; -var isHTMLForm = kindOfTest("HTMLFormElement"); -var toCamelCase = (str) => { - return str.toLowerCase().replace( - /[-_\s]([a-z\d])(\w*)/g, - function replacer(m, p1, p2) { - return p1.toUpperCase() + p2; - } - ); -}; -var hasOwnProperty = (({ hasOwnProperty: hasOwnProperty2 }) => (obj, prop) => hasOwnProperty2.call(obj, prop))(Object.prototype); -var isRegExp = kindOfTest("RegExp"); -var reduceDescriptors = (obj, reducer) => { - const descriptors2 = Object.getOwnPropertyDescriptors(obj); - const reducedDescriptors = {}; - forEach(descriptors2, (descriptor, name) => { - let ret; - if ((ret = reducer(descriptor, name, obj)) !== false) { - reducedDescriptors[name] = ret || descriptor; - } - }); - Object.defineProperties(obj, reducedDescriptors); -}; -var freezeMethods = (obj) => { - reduceDescriptors(obj, (descriptor, name) => { - if (isFunction(obj) && ["arguments", "caller", "callee"].indexOf(name) !== -1) { - return false; - } - const value = obj[name]; - if (!isFunction(value)) - return; - descriptor.enumerable = false; - if ("writable" in descriptor) { - descriptor.writable = false; - return; - } - if (!descriptor.set) { - descriptor.set = () => { - throw Error("Can not rewrite read-only method '" + name + "'"); - }; - } - }); -}; -var toObjectSet = (arrayOrString, delimiter) => { - const obj = {}; - const define = (arr) => { - arr.forEach((value) => { - obj[value] = true; - }); - }; - isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter)); - return obj; -}; -var noop = () => { -}; -var toFiniteNumber = (value, defaultValue) => { - value = +value; - return Number.isFinite(value) ? value : defaultValue; -}; -var ALPHA = "abcdefghijklmnopqrstuvwxyz"; -var DIGIT = "0123456789"; -var ALPHABET = { - DIGIT, - ALPHA, - ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT -}; -var generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => { - let str = ""; - const { length } = alphabet; - while (size--) { - str += alphabet[Math.random() * length | 0]; - } - return str; -}; -function isSpecCompliantForm(thing) { - return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === "FormData" && thing[Symbol.iterator]); -} -var toJSONObject = (obj) => { - const stack = new Array(10); - const visit = (source, i) => { - if (isObject(source)) { - if (stack.indexOf(source) >= 0) { - return; - } - if (!("toJSON" in source)) { - stack[i] = source; - const target = isArray(source) ? [] : {}; - forEach(source, (value, key) => { - const reducedValue = visit(value, i + 1); - !isUndefined(reducedValue) && (target[key] = reducedValue); - }); - stack[i] = void 0; - return target; - } - } - return source; - }; - return visit(obj, 0); -}; -var isAsyncFn = kindOfTest("AsyncFunction"); -var isThenable = (thing) => thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch); -var utils_default = { - isArray, - isArrayBuffer, - isBuffer, - isFormData, - isArrayBufferView, - isString, - isNumber, - isBoolean, - isObject, - isPlainObject, - isUndefined, - isDate, - isFile, - isBlob, - isRegExp, - isFunction, - isStream, - isURLSearchParams, - isTypedArray, - isFileList, - forEach, - merge, - extend, - trim, - stripBOM, - inherits, - toFlatObject, - kindOf, - kindOfTest, - endsWith, - toArray, - forEachEntry, - matchAll, - isHTMLForm, - hasOwnProperty, - hasOwnProp: hasOwnProperty, - // an alias to avoid ESLint no-prototype-builtins detection - reduceDescriptors, - freezeMethods, - toObjectSet, - toCamelCase, - noop, - toFiniteNumber, - findKey, - global: _global, - isContextDefined, - ALPHABET, - generateString, - isSpecCompliantForm, - toJSONObject, - isAsyncFn, - isThenable -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/AxiosError.js -function AxiosError(message, code, config, request, response) { - Error.call(this); - if (Error.captureStackTrace) { - Error.captureStackTrace(this, this.constructor); - } else { - this.stack = new Error().stack; - } - this.message = message; - this.name = "AxiosError"; - code && (this.code = code); - config && (this.config = config); - request && (this.request = request); - response && (this.response = response); -} -utils_default.inherits(AxiosError, Error, { - toJSON: function toJSON() { - return { - // Standard - message: this.message, - name: this.name, - // Microsoft - description: this.description, - number: this.number, - // Mozilla - fileName: this.fileName, - lineNumber: this.lineNumber, - columnNumber: this.columnNumber, - stack: this.stack, - // Axios - config: utils_default.toJSONObject(this.config), - code: this.code, - status: this.response && this.response.status ? this.response.status : null - }; - } -}); -var prototype = AxiosError.prototype; -var descriptors = {}; -[ - "ERR_BAD_OPTION_VALUE", - "ERR_BAD_OPTION", - "ECONNABORTED", - "ETIMEDOUT", - "ERR_NETWORK", - "ERR_FR_TOO_MANY_REDIRECTS", - "ERR_DEPRECATED", - "ERR_BAD_RESPONSE", - "ERR_BAD_REQUEST", - "ERR_CANCELED", - "ERR_NOT_SUPPORT", - "ERR_INVALID_URL" - // eslint-disable-next-line func-names -].forEach((code) => { - descriptors[code] = { value: code }; -}); -Object.defineProperties(AxiosError, descriptors); -Object.defineProperty(prototype, "isAxiosError", { value: true }); -AxiosError.from = (error, code, config, request, response, customProps) => { - const axiosError = Object.create(prototype); - utils_default.toFlatObject(error, axiosError, function filter2(obj) { - return obj !== Error.prototype; - }, (prop) => { - return prop !== "isAxiosError"; - }); - AxiosError.call(axiosError, error.message, code, config, request, response); - axiosError.cause = error; - axiosError.name = error.name; - customProps && Object.assign(axiosError, customProps); - return axiosError; -}; -var AxiosError_default = AxiosError; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/null.js -var null_default = null; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/toFormData.js -function isVisitable(thing) { - return utils_default.isPlainObject(thing) || utils_default.isArray(thing); -} -function removeBrackets(key) { - return utils_default.endsWith(key, "[]") ? key.slice(0, -2) : key; -} -function renderKey(path, key, dots) { - if (!path) - return key; - return path.concat(key).map(function each(token, i) { - token = removeBrackets(token); - return !dots && i ? "[" + token + "]" : token; - }).join(dots ? "." : ""); -} -function isFlatArray(arr) { - return utils_default.isArray(arr) && !arr.some(isVisitable); -} -var predicates = utils_default.toFlatObject(utils_default, {}, null, function filter(prop) { - return /^is[A-Z]/.test(prop); -}); -function toFormData(obj, formData, options) { - if (!utils_default.isObject(obj)) { - throw new TypeError("target must be an object"); - } - formData = formData || new (null_default || FormData)(); - options = utils_default.toFlatObject(options, { - metaTokens: true, - dots: false, - indexes: false - }, false, function defined(option, source) { - return !utils_default.isUndefined(source[option]); - }); - const metaTokens = options.metaTokens; - const visitor = options.visitor || defaultVisitor; - const dots = options.dots; - const indexes = options.indexes; - const _Blob = options.Blob || typeof Blob !== "undefined" && Blob; - const useBlob = _Blob && utils_default.isSpecCompliantForm(formData); - if (!utils_default.isFunction(visitor)) { - throw new TypeError("visitor must be a function"); - } - function convertValue(value) { - if (value === null) - return ""; - if (utils_default.isDate(value)) { - return value.toISOString(); - } - if (!useBlob && utils_default.isBlob(value)) { - throw new AxiosError_default("Blob is not supported. Use a Buffer instead."); - } - if (utils_default.isArrayBuffer(value) || utils_default.isTypedArray(value)) { - return useBlob && typeof Blob === "function" ? new Blob([value]) : Buffer.from(value); - } - return value; - } - function defaultVisitor(value, key, path) { - let arr = value; - if (value && !path && typeof value === "object") { - if (utils_default.endsWith(key, "{}")) { - key = metaTokens ? key : key.slice(0, -2); - value = JSON.stringify(value); - } else if (utils_default.isArray(value) && isFlatArray(value) || (utils_default.isFileList(value) || utils_default.endsWith(key, "[]")) && (arr = utils_default.toArray(value))) { - key = removeBrackets(key); - arr.forEach(function each(el, index) { - !(utils_default.isUndefined(el) || el === null) && formData.append( - // eslint-disable-next-line no-nested-ternary - indexes === true ? renderKey([key], index, dots) : indexes === null ? key : key + "[]", - convertValue(el) - ); - }); - return false; - } - } - if (isVisitable(value)) { - return true; - } - formData.append(renderKey(path, key, dots), convertValue(value)); - return false; - } - const stack = []; - const exposedHelpers = Object.assign(predicates, { - defaultVisitor, - convertValue, - isVisitable - }); - function build(value, path) { - if (utils_default.isUndefined(value)) - return; - if (stack.indexOf(value) !== -1) { - throw Error("Circular reference detected in " + path.join(".")); - } - stack.push(value); - utils_default.forEach(value, function each(el, key) { - const result = !(utils_default.isUndefined(el) || el === null) && visitor.call( - formData, - el, - utils_default.isString(key) ? key.trim() : key, - path, - exposedHelpers - ); - if (result === true) { - build(el, path ? path.concat(key) : [key]); - } - }); - stack.pop(); - } - if (!utils_default.isObject(obj)) { - throw new TypeError("data must be an object"); - } - build(obj); - return formData; -} -var toFormData_default = toFormData; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/AxiosURLSearchParams.js -function encode(str) { - const charMap = { - "!": "%21", - "'": "%27", - "(": "%28", - ")": "%29", - "~": "%7E", - "%20": "+", - "%00": "\0" - }; - return encodeURIComponent(str).replace(/[!'()~]|%20|%00/g, function replacer(match) { - return charMap[match]; - }); -} -function AxiosURLSearchParams(params, options) { - this._pairs = []; - params && toFormData_default(params, this, options); -} -var prototype2 = AxiosURLSearchParams.prototype; -prototype2.append = function append(name, value) { - this._pairs.push([name, value]); -}; -prototype2.toString = function toString2(encoder2) { - const _encode = encoder2 ? function(value) { - return encoder2.call(this, value, encode); - } : encode; - return this._pairs.map(function each(pair) { - return _encode(pair[0]) + "=" + _encode(pair[1]); - }, "").join("&"); -}; -var AxiosURLSearchParams_default = AxiosURLSearchParams; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/buildURL.js -function encode2(val) { - return encodeURIComponent(val).replace(/%3A/gi, ":").replace(/%24/g, "$").replace(/%2C/gi, ",").replace(/%20/g, "+").replace(/%5B/gi, "[").replace(/%5D/gi, "]"); -} -function buildURL(url, params, options) { - if (!params) { - return url; - } - const _encode = options && options.encode || encode2; - const serializeFn = options && options.serialize; - let serializedParams; - if (serializeFn) { - serializedParams = serializeFn(params, options); - } else { - serializedParams = utils_default.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams_default(params, options).toString(_encode); - } - if (serializedParams) { - const hashmarkIndex = url.indexOf("#"); - if (hashmarkIndex !== -1) { - url = url.slice(0, hashmarkIndex); - } - url += (url.indexOf("?") === -1 ? "?" : "&") + serializedParams; - } - return url; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/InterceptorManager.js -var InterceptorManager = class { - constructor() { - this.handlers = []; - } - /** - * Add a new interceptor to the stack - * - * @param {Function} fulfilled The function to handle `then` for a `Promise` - * @param {Function} rejected The function to handle `reject` for a `Promise` - * - * @return {Number} An ID used to remove interceptor later - */ - use(fulfilled, rejected, options) { - this.handlers.push({ - fulfilled, - rejected, - synchronous: options ? options.synchronous : false, - runWhen: options ? options.runWhen : null - }); - return this.handlers.length - 1; - } - /** - * Remove an interceptor from the stack - * - * @param {Number} id The ID that was returned by `use` - * - * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise - */ - eject(id) { - if (this.handlers[id]) { - this.handlers[id] = null; - } - } - /** - * Clear all interceptors from the stack - * - * @returns {void} - */ - clear() { - if (this.handlers) { - this.handlers = []; - } - } - /** - * Iterate over all the registered interceptors - * - * This method is particularly useful for skipping over any - * interceptors that may have become `null` calling `eject`. - * - * @param {Function} fn The function to call for each interceptor - * - * @returns {void} - */ - forEach(fn) { - utils_default.forEach(this.handlers, function forEachHandler(h) { - if (h !== null) { - fn(h); - } - }); - } -}; -var InterceptorManager_default = InterceptorManager; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/defaults/transitional.js -var transitional_default = { - silentJSONParsing: true, - forcedJSONParsing: true, - clarifyTimeoutError: false -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/classes/URLSearchParams.js -var URLSearchParams_default = typeof URLSearchParams !== "undefined" ? URLSearchParams : AxiosURLSearchParams_default; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/classes/FormData.js -var FormData_default = typeof FormData !== "undefined" ? FormData : null; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/classes/Blob.js -var Blob_default = typeof Blob !== "undefined" ? Blob : null; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/platform/browser/index.js -var isStandardBrowserEnv = (() => { - let product; - if (typeof navigator !== "undefined" && ((product = navigator.product) === "ReactNative" || product === "NativeScript" || product === "NS")) { - return false; - } - return typeof window !== "undefined" && typeof document !== "undefined"; -})(); -var isStandardBrowserWebWorkerEnv = (() => { - return typeof WorkerGlobalScope !== "undefined" && // eslint-disable-next-line no-undef - self instanceof WorkerGlobalScope && typeof self.importScripts === "function"; -})(); -var browser_default = { - isBrowser: true, - classes: { - URLSearchParams: URLSearchParams_default, - FormData: FormData_default, - Blob: Blob_default - }, - isStandardBrowserEnv, - isStandardBrowserWebWorkerEnv, - protocols: ["http", "https", "file", "blob", "url", "data"] -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/toURLEncodedForm.js -function toURLEncodedForm(data, options) { - return toFormData_default(data, new browser_default.classes.URLSearchParams(), Object.assign({ - visitor: function(value, key, path, helpers) { - if (browser_default.isNode && utils_default.isBuffer(value)) { - this.append(key, value.toString("base64")); - return false; - } - return helpers.defaultVisitor.apply(this, arguments); - } - }, options)); -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/formDataToJSON.js -function parsePropPath(name) { - return utils_default.matchAll(/\w+|\[(\w*)]/g, name).map((match) => { - return match[0] === "[]" ? "" : match[1] || match[0]; - }); -} -function arrayToObject(arr) { - const obj = {}; - const keys = Object.keys(arr); - let i; - const len = keys.length; - let key; - for (i = 0; i < len; i++) { - key = keys[i]; - obj[key] = arr[key]; - } - return obj; -} -function formDataToJSON(formData) { - function buildPath(path, value, target, index) { - let name = path[index++]; - const isNumericKey = Number.isFinite(+name); - const isLast = index >= path.length; - name = !name && utils_default.isArray(target) ? target.length : name; - if (isLast) { - if (utils_default.hasOwnProp(target, name)) { - target[name] = [target[name], value]; - } else { - target[name] = value; - } - return !isNumericKey; - } - if (!target[name] || !utils_default.isObject(target[name])) { - target[name] = []; - } - const result = buildPath(path, value, target[name], index); - if (result && utils_default.isArray(target[name])) { - target[name] = arrayToObject(target[name]); - } - return !isNumericKey; - } - if (utils_default.isFormData(formData) && utils_default.isFunction(formData.entries)) { - const obj = {}; - utils_default.forEachEntry(formData, (name, value) => { - buildPath(parsePropPath(name), value, obj, 0); - }); - return obj; - } - return null; -} -var formDataToJSON_default = formDataToJSON; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/defaults/index.js -function stringifySafely(rawValue, parser, encoder2) { - if (utils_default.isString(rawValue)) { - try { - (parser || JSON.parse)(rawValue); - return utils_default.trim(rawValue); - } catch (e) { - if (e.name !== "SyntaxError") { - throw e; - } - } - } - return (encoder2 || JSON.stringify)(rawValue); -} -var defaults = { - transitional: transitional_default, - adapter: ["xhr", "http"], - transformRequest: [function transformRequest(data, headers) { - const contentType = headers.getContentType() || ""; - const hasJSONContentType = contentType.indexOf("application/json") > -1; - const isObjectPayload = utils_default.isObject(data); - if (isObjectPayload && utils_default.isHTMLForm(data)) { - data = new FormData(data); - } - const isFormData2 = utils_default.isFormData(data); - if (isFormData2) { - if (!hasJSONContentType) { - return data; - } - return hasJSONContentType ? JSON.stringify(formDataToJSON_default(data)) : data; - } - if (utils_default.isArrayBuffer(data) || utils_default.isBuffer(data) || utils_default.isStream(data) || utils_default.isFile(data) || utils_default.isBlob(data)) { - return data; - } - if (utils_default.isArrayBufferView(data)) { - return data.buffer; - } - if (utils_default.isURLSearchParams(data)) { - headers.setContentType("application/x-www-form-urlencoded;charset=utf-8", false); - return data.toString(); - } - let isFileList2; - if (isObjectPayload) { - if (contentType.indexOf("application/x-www-form-urlencoded") > -1) { - return toURLEncodedForm(data, this.formSerializer).toString(); - } - if ((isFileList2 = utils_default.isFileList(data)) || contentType.indexOf("multipart/form-data") > -1) { - const _FormData = this.env && this.env.FormData; - return toFormData_default( - isFileList2 ? { "files[]": data } : data, - _FormData && new _FormData(), - this.formSerializer - ); - } - } - if (isObjectPayload || hasJSONContentType) { - headers.setContentType("application/json", false); - return stringifySafely(data); - } - return data; - }], - transformResponse: [function transformResponse(data) { - const transitional2 = this.transitional || defaults.transitional; - const forcedJSONParsing = transitional2 && transitional2.forcedJSONParsing; - const JSONRequested = this.responseType === "json"; - if (data && utils_default.isString(data) && (forcedJSONParsing && !this.responseType || JSONRequested)) { - const silentJSONParsing = transitional2 && transitional2.silentJSONParsing; - const strictJSONParsing = !silentJSONParsing && JSONRequested; - try { - return JSON.parse(data); - } catch (e) { - if (strictJSONParsing) { - if (e.name === "SyntaxError") { - throw AxiosError_default.from(e, AxiosError_default.ERR_BAD_RESPONSE, this, null, this.response); - } - throw e; - } - } - } - return data; - }], - /** - * A timeout in milliseconds to abort a request. If set to 0 (default) a - * timeout is not created. - */ - timeout: 0, - xsrfCookieName: "XSRF-TOKEN", - xsrfHeaderName: "X-XSRF-TOKEN", - maxContentLength: -1, - maxBodyLength: -1, - env: { - FormData: browser_default.classes.FormData, - Blob: browser_default.classes.Blob - }, - validateStatus: function validateStatus(status) { - return status >= 200 && status < 300; - }, - headers: { - common: { - "Accept": "application/json, text/plain, */*", - "Content-Type": void 0 - } - } -}; -utils_default.forEach(["delete", "get", "head", "post", "put", "patch"], (method) => { - defaults.headers[method] = {}; -}); -var defaults_default = defaults; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/parseHeaders.js -var ignoreDuplicateOf = utils_default.toObjectSet([ - "age", - "authorization", - "content-length", - "content-type", - "etag", - "expires", - "from", - "host", - "if-modified-since", - "if-unmodified-since", - "last-modified", - "location", - "max-forwards", - "proxy-authorization", - "referer", - "retry-after", - "user-agent" -]); -var parseHeaders_default = (rawHeaders) => { - const parsed = {}; - let key; - let val; - let i; - rawHeaders && rawHeaders.split("\n").forEach(function parser(line) { - i = line.indexOf(":"); - key = line.substring(0, i).trim().toLowerCase(); - val = line.substring(i + 1).trim(); - if (!key || parsed[key] && ignoreDuplicateOf[key]) { - return; - } - if (key === "set-cookie") { - if (parsed[key]) { - parsed[key].push(val); - } else { - parsed[key] = [val]; - } - } else { - parsed[key] = parsed[key] ? parsed[key] + ", " + val : val; - } - }); - return parsed; -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/AxiosHeaders.js -var $internals = Symbol("internals"); -function normalizeHeader(header) { - return header && String(header).trim().toLowerCase(); -} -function normalizeValue(value) { - if (value === false || value == null) { - return value; - } - return utils_default.isArray(value) ? value.map(normalizeValue) : String(value); -} -function parseTokens(str) { - const tokens = /* @__PURE__ */ Object.create(null); - const tokensRE = /([^\s,;=]+)\s*(?:=\s*([^,;]+))?/g; - let match; - while (match = tokensRE.exec(str)) { - tokens[match[1]] = match[2]; - } - return tokens; -} -var isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!#$%&'*+.]+$/.test(str.trim()); -function matchHeaderValue(context, value, header, filter2, isHeaderNameFilter) { - if (utils_default.isFunction(filter2)) { - return filter2.call(this, value, header); - } - if (isHeaderNameFilter) { - value = header; - } - if (!utils_default.isString(value)) - return; - if (utils_default.isString(filter2)) { - return value.indexOf(filter2) !== -1; - } - if (utils_default.isRegExp(filter2)) { - return filter2.test(value); - } -} -function formatHeader(header) { - return header.trim().toLowerCase().replace(/([a-z\d])(\w*)/g, (w, char, str) => { - return char.toUpperCase() + str; - }); -} -function buildAccessors(obj, header) { - const accessorName = utils_default.toCamelCase(" " + header); - ["get", "set", "has"].forEach((methodName) => { - Object.defineProperty(obj, methodName + accessorName, { - value: function(arg1, arg2, arg3) { - return this[methodName].call(this, header, arg1, arg2, arg3); - }, - configurable: true - }); - }); -} -var AxiosHeaders = class { - constructor(headers) { - headers && this.set(headers); - } - set(header, valueOrRewrite, rewrite) { - const self2 = this; - function setHeader(_value, _header, _rewrite) { - const lHeader = normalizeHeader(_header); - if (!lHeader) { - throw new Error("header name must be a non-empty string"); - } - const key = utils_default.findKey(self2, lHeader); - if (!key || self2[key] === void 0 || _rewrite === true || _rewrite === void 0 && self2[key] !== false) { - self2[key || _header] = normalizeValue(_value); - } - } - const setHeaders = (headers, _rewrite) => utils_default.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite)); - if (utils_default.isPlainObject(header) || header instanceof this.constructor) { - setHeaders(header, valueOrRewrite); - } else if (utils_default.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) { - setHeaders(parseHeaders_default(header), valueOrRewrite); - } else { - header != null && setHeader(valueOrRewrite, header, rewrite); - } - return this; - } - get(header, parser) { - header = normalizeHeader(header); - if (header) { - const key = utils_default.findKey(this, header); - if (key) { - const value = this[key]; - if (!parser) { - return value; - } - if (parser === true) { - return parseTokens(value); - } - if (utils_default.isFunction(parser)) { - return parser.call(this, value, key); - } - if (utils_default.isRegExp(parser)) { - return parser.exec(value); - } - throw new TypeError("parser must be boolean|regexp|function"); - } - } - } - has(header, matcher) { - header = normalizeHeader(header); - if (header) { - const key = utils_default.findKey(this, header); - return !!(key && this[key] !== void 0 && (!matcher || matchHeaderValue(this, this[key], key, matcher))); - } - return false; - } - delete(header, matcher) { - const self2 = this; - let deleted = false; - function deleteHeader(_header) { - _header = normalizeHeader(_header); - if (_header) { - const key = utils_default.findKey(self2, _header); - if (key && (!matcher || matchHeaderValue(self2, self2[key], key, matcher))) { - delete self2[key]; - deleted = true; - } - } - } - if (utils_default.isArray(header)) { - header.forEach(deleteHeader); - } else { - deleteHeader(header); - } - return deleted; - } - clear(matcher) { - const keys = Object.keys(this); - let i = keys.length; - let deleted = false; - while (i--) { - const key = keys[i]; - if (!matcher || matchHeaderValue(this, this[key], key, matcher, true)) { - delete this[key]; - deleted = true; - } - } - return deleted; - } - normalize(format) { - const self2 = this; - const headers = {}; - utils_default.forEach(this, (value, header) => { - const key = utils_default.findKey(headers, header); - if (key) { - self2[key] = normalizeValue(value); - delete self2[header]; - return; - } - const normalized = format ? formatHeader(header) : String(header).trim(); - if (normalized !== header) { - delete self2[header]; - } - self2[normalized] = normalizeValue(value); - headers[normalized] = true; - }); - return this; - } - concat(...targets) { - return this.constructor.concat(this, ...targets); - } - toJSON(asStrings) { - const obj = /* @__PURE__ */ Object.create(null); - utils_default.forEach(this, (value, header) => { - value != null && value !== false && (obj[header] = asStrings && utils_default.isArray(value) ? value.join(", ") : value); - }); - return obj; - } - [Symbol.iterator]() { - return Object.entries(this.toJSON())[Symbol.iterator](); - } - toString() { - return Object.entries(this.toJSON()).map(([header, value]) => header + ": " + value).join("\n"); - } - get [Symbol.toStringTag]() { - return "AxiosHeaders"; - } - static from(thing) { - return thing instanceof this ? thing : new this(thing); - } - static concat(first, ...targets) { - const computed = new this(first); - targets.forEach((target) => computed.set(target)); - return computed; - } - static accessor(header) { - const internals = this[$internals] = this[$internals] = { - accessors: {} - }; - const accessors = internals.accessors; - const prototype3 = this.prototype; - function defineAccessor(_header) { - const lHeader = normalizeHeader(_header); - if (!accessors[lHeader]) { - buildAccessors(prototype3, _header); - accessors[lHeader] = true; - } - } - utils_default.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header); - return this; - } -}; -AxiosHeaders.accessor(["Content-Type", "Content-Length", "Accept", "Accept-Encoding", "User-Agent", "Authorization"]); -utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => { - let mapped = key[0].toUpperCase() + key.slice(1); - return { - get: () => value, - set(headerValue) { - this[mapped] = headerValue; - } - }; -}); -utils_default.freezeMethods(AxiosHeaders); -var AxiosHeaders_default = AxiosHeaders; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/transformData.js -function transformData(fns, response) { - const config = this || defaults_default; - const context = response || config; - const headers = AxiosHeaders_default.from(context.headers); - let data = context.data; - utils_default.forEach(fns, function transform(fn) { - data = fn.call(config, data, headers.normalize(), response ? response.status : void 0); - }); - headers.normalize(); - return data; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/cancel/isCancel.js -function isCancel(value) { - return !!(value && value.__CANCEL__); -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/cancel/CanceledError.js -function CanceledError(message, config, request) { - AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request); - this.name = "CanceledError"; -} -utils_default.inherits(CanceledError, AxiosError_default, { - __CANCEL__: true -}); -var CanceledError_default = CanceledError; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/settle.js -function settle(resolve, reject, response) { - const validateStatus2 = response.config.validateStatus; - if (!response.status || !validateStatus2 || validateStatus2(response.status)) { - resolve(response); - } else { - reject(new AxiosError_default( - "Request failed with status code " + response.status, - [AxiosError_default.ERR_BAD_REQUEST, AxiosError_default.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4], - response.config, - response.request, - response - )); - } -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/cookies.js -var cookies_default = browser_default.isStandardBrowserEnv ? ( - // Standard browser envs support document.cookie - function standardBrowserEnv() { - return { - write: function write(name, value, expires, path, domain, secure) { - const cookie = []; - cookie.push(name + "=" + encodeURIComponent(value)); - if (utils_default.isNumber(expires)) { - cookie.push("expires=" + new Date(expires).toGMTString()); - } - if (utils_default.isString(path)) { - cookie.push("path=" + path); - } - if (utils_default.isString(domain)) { - cookie.push("domain=" + domain); - } - if (secure === true) { - cookie.push("secure"); - } - document.cookie = cookie.join("; "); - }, - read: function read(name) { - const match = document.cookie.match(new RegExp("(^|;\\s*)(" + name + ")=([^;]*)")); - return match ? decodeURIComponent(match[3]) : null; - }, - remove: function remove(name) { - this.write(name, "", Date.now() - 864e5); - } - }; - }() -) : ( - // Non standard browser env (web workers, react-native) lack needed support. - function nonStandardBrowserEnv() { - return { - write: function write() { - }, - read: function read() { - return null; - }, - remove: function remove() { - } - }; - }() -); - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/isAbsoluteURL.js -function isAbsoluteURL(url) { - return /^([a-z][a-z\d+\-.]*:)?\/\//i.test(url); -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/combineURLs.js -function combineURLs(baseURL, relativeURL) { - return relativeURL ? baseURL.replace(/\/+$/, "") + "/" + relativeURL.replace(/^\/+/, "") : baseURL; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/buildFullPath.js -function buildFullPath(baseURL, requestedURL) { - if (baseURL && !isAbsoluteURL(requestedURL)) { - return combineURLs(baseURL, requestedURL); - } - return requestedURL; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/isURLSameOrigin.js -var isURLSameOrigin_default = browser_default.isStandardBrowserEnv ? ( - // Standard browser envs have full support of the APIs needed to test - // whether the request URL is of the same origin as current location. - function standardBrowserEnv2() { - const msie = /(msie|trident)/i.test(navigator.userAgent); - const urlParsingNode = document.createElement("a"); - let originURL; - function resolveURL(url) { - let href = url; - if (msie) { - urlParsingNode.setAttribute("href", href); - href = urlParsingNode.href; - } - urlParsingNode.setAttribute("href", href); - return { - href: urlParsingNode.href, - protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, "") : "", - host: urlParsingNode.host, - search: urlParsingNode.search ? urlParsingNode.search.replace(/^\?/, "") : "", - hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^#/, "") : "", - hostname: urlParsingNode.hostname, - port: urlParsingNode.port, - pathname: urlParsingNode.pathname.charAt(0) === "/" ? urlParsingNode.pathname : "/" + urlParsingNode.pathname - }; - } - originURL = resolveURL(window.location.href); - return function isURLSameOrigin(requestURL) { - const parsed = utils_default.isString(requestURL) ? resolveURL(requestURL) : requestURL; - return parsed.protocol === originURL.protocol && parsed.host === originURL.host; - }; - }() -) : ( - // Non standard browser envs (web workers, react-native) lack needed support. - function nonStandardBrowserEnv2() { - return function isURLSameOrigin() { - return true; - }; - }() -); - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/parseProtocol.js -function parseProtocol(url) { - const match = /^([-+\w]{1,25})(:?\/\/|:)/.exec(url); - return match && match[1] || ""; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/speedometer.js -function speedometer(samplesCount, min) { - samplesCount = samplesCount || 10; - const bytes = new Array(samplesCount); - const timestamps = new Array(samplesCount); - let head = 0; - let tail = 0; - let firstSampleTS; - min = min !== void 0 ? min : 1e3; - return function push(chunkLength) { - const now = Date.now(); - const startedAt = timestamps[tail]; - if (!firstSampleTS) { - firstSampleTS = now; - } - bytes[head] = chunkLength; - timestamps[head] = now; - let i = tail; - let bytesCount = 0; - while (i !== head) { - bytesCount += bytes[i++]; - i = i % samplesCount; - } - head = (head + 1) % samplesCount; - if (head === tail) { - tail = (tail + 1) % samplesCount; - } - if (now - firstSampleTS < min) { - return; - } - const passed = startedAt && now - startedAt; - return passed ? Math.round(bytesCount * 1e3 / passed) : void 0; - }; -} -var speedometer_default = speedometer; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/adapters/xhr.js -function progressEventReducer(listener, isDownloadStream) { - let bytesNotified = 0; - const _speedometer = speedometer_default(50, 250); - return (e) => { - const loaded = e.loaded; - const total = e.lengthComputable ? e.total : void 0; - const progressBytes = loaded - bytesNotified; - const rate = _speedometer(progressBytes); - const inRange = loaded <= total; - bytesNotified = loaded; - const data = { - loaded, - total, - progress: total ? loaded / total : void 0, - bytes: progressBytes, - rate: rate ? rate : void 0, - estimated: rate && total && inRange ? (total - loaded) / rate : void 0, - event: e - }; - data[isDownloadStream ? "download" : "upload"] = true; - listener(data); - }; -} -var isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined"; -var xhr_default = isXHRAdapterSupported && function(config) { - return new Promise(function dispatchXhrRequest(resolve, reject) { - let requestData = config.data; - const requestHeaders = AxiosHeaders_default.from(config.headers).normalize(); - const responseType = config.responseType; - let onCanceled; - function done() { - if (config.cancelToken) { - config.cancelToken.unsubscribe(onCanceled); - } - if (config.signal) { - config.signal.removeEventListener("abort", onCanceled); - } - } - let contentType; - if (utils_default.isFormData(requestData)) { - if (browser_default.isStandardBrowserEnv || browser_default.isStandardBrowserWebWorkerEnv) { - requestHeaders.setContentType(false); - } else if (!requestHeaders.getContentType(/^\s*multipart\/form-data/)) { - requestHeaders.setContentType("multipart/form-data"); - } else if (utils_default.isString(contentType = requestHeaders.getContentType())) { - requestHeaders.setContentType(contentType.replace(/^\s*(multipart\/form-data);+/, "$1")); - } - } - let request = new XMLHttpRequest(); - if (config.auth) { - const username = config.auth.username || ""; - const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : ""; - requestHeaders.set("Authorization", "Basic " + btoa(username + ":" + password)); - } - const fullPath = buildFullPath(config.baseURL, config.url); - request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); - request.timeout = config.timeout; - function onloadend() { - if (!request) { - return; - } - const responseHeaders = AxiosHeaders_default.from( - "getAllResponseHeaders" in request && request.getAllResponseHeaders() - ); - const responseData = !responseType || responseType === "text" || responseType === "json" ? request.responseText : request.response; - const response = { - data: responseData, - status: request.status, - statusText: request.statusText, - headers: responseHeaders, - config, - request - }; - settle(function _resolve(value) { - resolve(value); - done(); - }, function _reject(err) { - reject(err); - done(); - }, response); - request = null; - } - if ("onloadend" in request) { - request.onloadend = onloadend; - } else { - request.onreadystatechange = function handleLoad() { - if (!request || request.readyState !== 4) { - return; - } - if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf("file:") === 0)) { - return; - } - setTimeout(onloadend); - }; - } - request.onabort = function handleAbort() { - if (!request) { - return; - } - reject(new AxiosError_default("Request aborted", AxiosError_default.ECONNABORTED, config, request)); - request = null; - }; - request.onerror = function handleError() { - reject(new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config, request)); - request = null; - }; - request.ontimeout = function handleTimeout() { - let timeoutErrorMessage = config.timeout ? "timeout of " + config.timeout + "ms exceeded" : "timeout exceeded"; - const transitional2 = config.transitional || transitional_default; - if (config.timeoutErrorMessage) { - timeoutErrorMessage = config.timeoutErrorMessage; - } - reject(new AxiosError_default( - timeoutErrorMessage, - transitional2.clarifyTimeoutError ? AxiosError_default.ETIMEDOUT : AxiosError_default.ECONNABORTED, - config, - request - )); - request = null; - }; - if (browser_default.isStandardBrowserEnv) { - const xsrfValue = isURLSameOrigin_default(fullPath) && config.xsrfCookieName && cookies_default.read(config.xsrfCookieName); - if (xsrfValue) { - requestHeaders.set(config.xsrfHeaderName, xsrfValue); - } - } - requestData === void 0 && requestHeaders.setContentType(null); - if ("setRequestHeader" in request) { - utils_default.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) { - request.setRequestHeader(key, val); - }); - } - if (!utils_default.isUndefined(config.withCredentials)) { - request.withCredentials = !!config.withCredentials; - } - if (responseType && responseType !== "json") { - request.responseType = config.responseType; - } - if (typeof config.onDownloadProgress === "function") { - request.addEventListener("progress", progressEventReducer(config.onDownloadProgress, true)); - } - if (typeof config.onUploadProgress === "function" && request.upload) { - request.upload.addEventListener("progress", progressEventReducer(config.onUploadProgress)); - } - if (config.cancelToken || config.signal) { - onCanceled = (cancel) => { - if (!request) { - return; - } - reject(!cancel || cancel.type ? new CanceledError_default(null, config, request) : cancel); - request.abort(); - request = null; - }; - config.cancelToken && config.cancelToken.subscribe(onCanceled); - if (config.signal) { - config.signal.aborted ? onCanceled() : config.signal.addEventListener("abort", onCanceled); - } - } - const protocol = parseProtocol(fullPath); - if (protocol && browser_default.protocols.indexOf(protocol) === -1) { - reject(new AxiosError_default("Unsupported protocol " + protocol + ":", AxiosError_default.ERR_BAD_REQUEST, config)); - return; - } - request.send(requestData || null); - }); -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/adapters/adapters.js -var knownAdapters = { - http: null_default, - xhr: xhr_default -}; -utils_default.forEach(knownAdapters, (fn, value) => { - if (fn) { - try { - Object.defineProperty(fn, "name", { value }); - } catch (e) { - } - Object.defineProperty(fn, "adapterName", { value }); - } -}); -var renderReason = (reason) => `- ${reason}`; -var isResolvedHandle = (adapter) => utils_default.isFunction(adapter) || adapter === null || adapter === false; -var adapters_default = { - getAdapter: (adapters) => { - adapters = utils_default.isArray(adapters) ? adapters : [adapters]; - const { length } = adapters; - let nameOrAdapter; - let adapter; - const rejectedReasons = {}; - for (let i = 0; i < length; i++) { - nameOrAdapter = adapters[i]; - let id; - adapter = nameOrAdapter; - if (!isResolvedHandle(nameOrAdapter)) { - adapter = knownAdapters[(id = String(nameOrAdapter)).toLowerCase()]; - if (adapter === void 0) { - throw new AxiosError_default(`Unknown adapter '${id}'`); - } - } - if (adapter) { - break; - } - rejectedReasons[id || "#" + i] = adapter; - } - if (!adapter) { - const reasons = Object.entries(rejectedReasons).map( - ([id, state]) => `adapter ${id} ` + (state === false ? "is not supported by the environment" : "is not available in the build") - ); - let s = length ? reasons.length > 1 ? "since :\n" + reasons.map(renderReason).join("\n") : " " + renderReason(reasons[0]) : "as no adapter specified"; - throw new AxiosError_default( - `There is no suitable adapter to dispatch the request ` + s, - "ERR_NOT_SUPPORT" - ); - } - return adapter; - }, - adapters: knownAdapters -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/dispatchRequest.js -function throwIfCancellationRequested(config) { - if (config.cancelToken) { - config.cancelToken.throwIfRequested(); - } - if (config.signal && config.signal.aborted) { - throw new CanceledError_default(null, config); - } -} -function dispatchRequest(config) { - throwIfCancellationRequested(config); - config.headers = AxiosHeaders_default.from(config.headers); - config.data = transformData.call( - config, - config.transformRequest - ); - if (["post", "put", "patch"].indexOf(config.method) !== -1) { - config.headers.setContentType("application/x-www-form-urlencoded", false); - } - const adapter = adapters_default.getAdapter(config.adapter || defaults_default.adapter); - return adapter(config).then(function onAdapterResolution(response) { - throwIfCancellationRequested(config); - response.data = transformData.call( - config, - config.transformResponse, - response - ); - response.headers = AxiosHeaders_default.from(response.headers); - return response; - }, function onAdapterRejection(reason) { - if (!isCancel(reason)) { - throwIfCancellationRequested(config); - if (reason && reason.response) { - reason.response.data = transformData.call( - config, - config.transformResponse, - reason.response - ); - reason.response.headers = AxiosHeaders_default.from(reason.response.headers); - } - } - return Promise.reject(reason); - }); -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/mergeConfig.js -var headersToObject = (thing) => thing instanceof AxiosHeaders_default ? thing.toJSON() : thing; -function mergeConfig(config1, config2) { - config2 = config2 || {}; - const config = {}; - function getMergedValue(target, source, caseless) { - if (utils_default.isPlainObject(target) && utils_default.isPlainObject(source)) { - return utils_default.merge.call({ caseless }, target, source); - } else if (utils_default.isPlainObject(source)) { - return utils_default.merge({}, source); - } else if (utils_default.isArray(source)) { - return source.slice(); - } - return source; - } - function mergeDeepProperties(a, b, caseless) { - if (!utils_default.isUndefined(b)) { - return getMergedValue(a, b, caseless); - } else if (!utils_default.isUndefined(a)) { - return getMergedValue(void 0, a, caseless); - } - } - function valueFromConfig2(a, b) { - if (!utils_default.isUndefined(b)) { - return getMergedValue(void 0, b); - } - } - function defaultToConfig2(a, b) { - if (!utils_default.isUndefined(b)) { - return getMergedValue(void 0, b); - } else if (!utils_default.isUndefined(a)) { - return getMergedValue(void 0, a); - } - } - function mergeDirectKeys(a, b, prop) { - if (prop in config2) { - return getMergedValue(a, b); - } else if (prop in config1) { - return getMergedValue(void 0, a); - } - } - const mergeMap = { - url: valueFromConfig2, - method: valueFromConfig2, - data: valueFromConfig2, - baseURL: defaultToConfig2, - transformRequest: defaultToConfig2, - transformResponse: defaultToConfig2, - paramsSerializer: defaultToConfig2, - timeout: defaultToConfig2, - timeoutMessage: defaultToConfig2, - withCredentials: defaultToConfig2, - adapter: defaultToConfig2, - responseType: defaultToConfig2, - xsrfCookieName: defaultToConfig2, - xsrfHeaderName: defaultToConfig2, - onUploadProgress: defaultToConfig2, - onDownloadProgress: defaultToConfig2, - decompress: defaultToConfig2, - maxContentLength: defaultToConfig2, - maxBodyLength: defaultToConfig2, - beforeRedirect: defaultToConfig2, - transport: defaultToConfig2, - httpAgent: defaultToConfig2, - httpsAgent: defaultToConfig2, - cancelToken: defaultToConfig2, - socketPath: defaultToConfig2, - responseEncoding: defaultToConfig2, - validateStatus: mergeDirectKeys, - headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true) - }; - utils_default.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) { - const merge2 = mergeMap[prop] || mergeDeepProperties; - const configValue = merge2(config1[prop], config2[prop], prop); - utils_default.isUndefined(configValue) && merge2 !== mergeDirectKeys || (config[prop] = configValue); - }); - return config; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/env/data.js -var VERSION = "1.6.0"; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/validator.js -var validators = {}; -["object", "boolean", "number", "function", "string", "symbol"].forEach((type, i) => { - validators[type] = function validator(thing) { - return typeof thing === type || "a" + (i < 1 ? "n " : " ") + type; - }; -}); -var deprecatedWarnings = {}; -validators.transitional = function transitional(validator, version2, message) { - function formatMessage(opt, desc) { - return "[Axios v" + VERSION + "] Transitional option '" + opt + "'" + desc + (message ? ". " + message : ""); - } - return (value, opt, opts) => { - if (validator === false) { - throw new AxiosError_default( - formatMessage(opt, " has been removed" + (version2 ? " in " + version2 : "")), - AxiosError_default.ERR_DEPRECATED - ); - } - if (version2 && !deprecatedWarnings[opt]) { - deprecatedWarnings[opt] = true; - console.warn( - formatMessage( - opt, - " has been deprecated since v" + version2 + " and will be removed in the near future" - ) - ); - } - return validator ? validator(value, opt, opts) : true; - }; -}; -function assertOptions(options, schema, allowUnknown) { - if (typeof options !== "object") { - throw new AxiosError_default("options must be an object", AxiosError_default.ERR_BAD_OPTION_VALUE); - } - const keys = Object.keys(options); - let i = keys.length; - while (i-- > 0) { - const opt = keys[i]; - const validator = schema[opt]; - if (validator) { - const value = options[opt]; - const result = value === void 0 || validator(value, opt, options); - if (result !== true) { - throw new AxiosError_default("option " + opt + " must be " + result, AxiosError_default.ERR_BAD_OPTION_VALUE); - } - continue; - } - if (allowUnknown !== true) { - throw new AxiosError_default("Unknown option " + opt, AxiosError_default.ERR_BAD_OPTION); - } - } -} -var validator_default = { - assertOptions, - validators -}; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/core/Axios.js -var validators2 = validator_default.validators; -var Axios = class { - constructor(instanceConfig) { - this.defaults = instanceConfig; - this.interceptors = { - request: new InterceptorManager_default(), - response: new InterceptorManager_default() - }; - } - /** - * Dispatch a request - * - * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults) - * @param {?Object} config - * - * @returns {Promise} The Promise to be fulfilled - */ - request(configOrUrl, config) { - if (typeof configOrUrl === "string") { - config = config || {}; - config.url = configOrUrl; - } else { - config = configOrUrl || {}; - } - config = mergeConfig(this.defaults, config); - const { transitional: transitional2, paramsSerializer, headers } = config; - if (transitional2 !== void 0) { - validator_default.assertOptions(transitional2, { - silentJSONParsing: validators2.transitional(validators2.boolean), - forcedJSONParsing: validators2.transitional(validators2.boolean), - clarifyTimeoutError: validators2.transitional(validators2.boolean) - }, false); - } - if (paramsSerializer != null) { - if (utils_default.isFunction(paramsSerializer)) { - config.paramsSerializer = { - serialize: paramsSerializer - }; - } else { - validator_default.assertOptions(paramsSerializer, { - encode: validators2.function, - serialize: validators2.function - }, true); - } - } - config.method = (config.method || this.defaults.method || "get").toLowerCase(); - let contextHeaders = headers && utils_default.merge( - headers.common, - headers[config.method] - ); - headers && utils_default.forEach( - ["delete", "get", "head", "post", "put", "patch", "common"], - (method) => { - delete headers[method]; - } - ); - config.headers = AxiosHeaders_default.concat(contextHeaders, headers); - const requestInterceptorChain = []; - let synchronousRequestInterceptors = true; - this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) { - if (typeof interceptor.runWhen === "function" && interceptor.runWhen(config) === false) { - return; - } - synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous; - requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected); - }); - const responseInterceptorChain = []; - this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) { - responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected); - }); - let promise; - let i = 0; - let len; - if (!synchronousRequestInterceptors) { - const chain = [dispatchRequest.bind(this), void 0]; - chain.unshift.apply(chain, requestInterceptorChain); - chain.push.apply(chain, responseInterceptorChain); - len = chain.length; - promise = Promise.resolve(config); - while (i < len) { - promise = promise.then(chain[i++], chain[i++]); - } - return promise; - } - len = requestInterceptorChain.length; - let newConfig = config; - i = 0; - while (i < len) { - const onFulfilled = requestInterceptorChain[i++]; - const onRejected = requestInterceptorChain[i++]; - try { - newConfig = onFulfilled(newConfig); - } catch (error) { - onRejected.call(this, error); - break; - } - } - try { - promise = dispatchRequest.call(this, newConfig); - } catch (error) { - return Promise.reject(error); - } - i = 0; - len = responseInterceptorChain.length; - while (i < len) { - promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]); - } - return promise; - } - getUri(config) { - config = mergeConfig(this.defaults, config); - const fullPath = buildFullPath(config.baseURL, config.url); - return buildURL(fullPath, config.params, config.paramsSerializer); - } -}; -utils_default.forEach(["delete", "get", "head", "options"], function forEachMethodNoData(method) { - Axios.prototype[method] = function(url, config) { - return this.request(mergeConfig(config || {}, { - method, - url, - data: (config || {}).data - })); - }; -}); -utils_default.forEach(["post", "put", "patch"], function forEachMethodWithData(method) { - function generateHTTPMethod(isForm) { - return function httpMethod(url, data, config) { - return this.request(mergeConfig(config || {}, { - method, - headers: isForm ? { - "Content-Type": "multipart/form-data" - } : {}, - url, - data - })); - }; - } - Axios.prototype[method] = generateHTTPMethod(); - Axios.prototype[method + "Form"] = generateHTTPMethod(true); -}); -var Axios_default = Axios; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/cancel/CancelToken.js -var CancelToken = class _CancelToken { - constructor(executor) { - if (typeof executor !== "function") { - throw new TypeError("executor must be a function."); - } - let resolvePromise; - this.promise = new Promise(function promiseExecutor(resolve) { - resolvePromise = resolve; - }); - const token = this; - this.promise.then((cancel) => { - if (!token._listeners) - return; - let i = token._listeners.length; - while (i-- > 0) { - token._listeners[i](cancel); - } - token._listeners = null; - }); - this.promise.then = (onfulfilled) => { - let _resolve; - const promise = new Promise((resolve) => { - token.subscribe(resolve); - _resolve = resolve; - }).then(onfulfilled); - promise.cancel = function reject() { - token.unsubscribe(_resolve); - }; - return promise; - }; - executor(function cancel(message, config, request) { - if (token.reason) { - return; - } - token.reason = new CanceledError_default(message, config, request); - resolvePromise(token.reason); - }); - } - /** - * Throws a `CanceledError` if cancellation has been requested. - */ - throwIfRequested() { - if (this.reason) { - throw this.reason; - } - } - /** - * Subscribe to the cancel signal - */ - subscribe(listener) { - if (this.reason) { - listener(this.reason); - return; - } - if (this._listeners) { - this._listeners.push(listener); - } else { - this._listeners = [listener]; - } - } - /** - * Unsubscribe from the cancel signal - */ - unsubscribe(listener) { - if (!this._listeners) { - return; - } - const index = this._listeners.indexOf(listener); - if (index !== -1) { - this._listeners.splice(index, 1); - } - } - /** - * Returns an object that contains a new `CancelToken` and a function that, when called, - * cancels the `CancelToken`. - */ - static source() { - let cancel; - const token = new _CancelToken(function executor(c) { - cancel = c; - }); - return { - token, - cancel - }; - } -}; -var CancelToken_default = CancelToken; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/spread.js -function spread(callback) { - return function wrap(arr) { - return callback.apply(null, arr); - }; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/isAxiosError.js -function isAxiosError(payload) { - return utils_default.isObject(payload) && payload.isAxiosError === true; -} - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/helpers/HttpStatusCode.js -var HttpStatusCode = { - Continue: 100, - SwitchingProtocols: 101, - Processing: 102, - EarlyHints: 103, - Ok: 200, - Created: 201, - Accepted: 202, - NonAuthoritativeInformation: 203, - NoContent: 204, - ResetContent: 205, - PartialContent: 206, - MultiStatus: 207, - AlreadyReported: 208, - ImUsed: 226, - MultipleChoices: 300, - MovedPermanently: 301, - Found: 302, - SeeOther: 303, - NotModified: 304, - UseProxy: 305, - Unused: 306, - TemporaryRedirect: 307, - PermanentRedirect: 308, - BadRequest: 400, - Unauthorized: 401, - PaymentRequired: 402, - Forbidden: 403, - NotFound: 404, - MethodNotAllowed: 405, - NotAcceptable: 406, - ProxyAuthenticationRequired: 407, - RequestTimeout: 408, - Conflict: 409, - Gone: 410, - LengthRequired: 411, - PreconditionFailed: 412, - PayloadTooLarge: 413, - UriTooLong: 414, - UnsupportedMediaType: 415, - RangeNotSatisfiable: 416, - ExpectationFailed: 417, - ImATeapot: 418, - MisdirectedRequest: 421, - UnprocessableEntity: 422, - Locked: 423, - FailedDependency: 424, - TooEarly: 425, - UpgradeRequired: 426, - PreconditionRequired: 428, - TooManyRequests: 429, - RequestHeaderFieldsTooLarge: 431, - UnavailableForLegalReasons: 451, - InternalServerError: 500, - NotImplemented: 501, - BadGateway: 502, - ServiceUnavailable: 503, - GatewayTimeout: 504, - HttpVersionNotSupported: 505, - VariantAlsoNegotiates: 506, - InsufficientStorage: 507, - LoopDetected: 508, - NotExtended: 510, - NetworkAuthenticationRequired: 511 -}; -Object.entries(HttpStatusCode).forEach(([key, value]) => { - HttpStatusCode[value] = key; -}); -var HttpStatusCode_default = HttpStatusCode; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/lib/axios.js -function createInstance(defaultConfig) { - const context = new Axios_default(defaultConfig); - const instance = bind(Axios_default.prototype.request, context); - utils_default.extend(instance, Axios_default.prototype, context, { allOwnKeys: true }); - utils_default.extend(instance, context, null, { allOwnKeys: true }); - instance.create = function create(instanceConfig) { - return createInstance(mergeConfig(defaultConfig, instanceConfig)); - }; - return instance; -} -var axios = createInstance(defaults_default); -axios.Axios = Axios_default; -axios.CanceledError = CanceledError_default; -axios.CancelToken = CancelToken_default; -axios.isCancel = isCancel; -axios.VERSION = VERSION; -axios.toFormData = toFormData_default; -axios.AxiosError = AxiosError_default; -axios.Cancel = axios.CanceledError; -axios.all = function all(promises) { - return Promise.all(promises); -}; -axios.spread = spread; -axios.isAxiosError = isAxiosError; -axios.mergeConfig = mergeConfig; -axios.AxiosHeaders = AxiosHeaders_default; -axios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing); -axios.getAdapter = adapters_default.getAdapter; -axios.HttpStatusCode = HttpStatusCode_default; -axios.default = axios; -var axios_default = axios; - -// node_modules/.pnpm/axios@1.6.0/node_modules/axios/index.js -var { - Axios: Axios2, - AxiosError: AxiosError2, - CanceledError: CanceledError2, - isCancel: isCancel2, - CancelToken: CancelToken2, - VERSION: VERSION2, - all: all2, - Cancel, - isAxiosError: isAxiosError2, - spread: spread2, - toFormData: toFormData2, - AxiosHeaders: AxiosHeaders2, - HttpStatusCode: HttpStatusCode2, - formToJSON, - getAdapter, - mergeConfig: mergeConfig2 -} = axios_default; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/createWebWorkerPromise.js -var import_webworker_promise = __toESM(require_src(), 1); -async function createWebWorkerPromise(existingWorker, pipelineWorkerUrl3) { - let workerPromise; - if (existingWorker != null) { - const itkWebWorker2 = existingWorker; - if (itkWebWorker2.workerPromise !== void 0) { - workerPromise = itkWebWorker2.workerPromise; - } else { - workerPromise = new import_webworker_promise.default(existingWorker); - } - return await Promise.resolve({ webworkerPromise: workerPromise, worker: existingWorker }); - } - const workerUrl = typeof pipelineWorkerUrl3 === "undefined" ? itkConfig_default.pipelineWorkerUrl : pipelineWorkerUrl3; - let worker = null; - const webWorkersUrl = itkConfig_default.webWorkersUrl; - if (typeof webWorkersUrl !== "undefined") { - console.warn("itkConfig webWorkersUrl is deprecated. Please use pipelineWorkerUrl with the full path to the pipeline worker."); - const min = "min."; - const webWorkerString = webWorkersUrl; - if (webWorkerString.startsWith("http")) { - const response = await axios_default.get(`${webWorkerString}/bundles/pipeline.${min}worker.js`, { responseType: "blob" }); - const workerObjectUrl = URL.createObjectURL(response.data); - worker = new Worker(workerObjectUrl, { type: "module" }); - } else { - worker = new Worker(`${webWorkerString}/bundles/pipeline.${min}worker.js`, { type: "module" }); - } - } else if (workerUrl === null) { - worker = new Worker(new URL("./web-workers/itk-wasm-pipeline.worker.js", import.meta.url), { type: "module" }); - } else { - if (workerUrl.startsWith("http")) { - const response = await axios_default.get(workerUrl, { responseType: "blob" }); - const workerObjectUrl = URL.createObjectURL(response.data); - worker = new Worker(workerObjectUrl, { type: "module" }); - } else { - worker = new Worker(workerUrl, { type: "module" }); - } - } - const webworkerPromise = new import_webworker_promise.default(worker); - const itkWebWorker = worker; - itkWebWorker.workerPromise = webworkerPromise; - return { webworkerPromise, worker: itkWebWorker }; -} -var createWebWorkerPromise_default = createWebWorkerPromise; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/pipeline-worker-url.js -var pipelineWorkerUrl; -function getPipelineWorkerUrl() { - return pipelineWorkerUrl; -} - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/pipelines-base-url.js -var pipelinesBaseUrl; -function getPipelinesBaseUrl() { - return pipelinesBaseUrl; -} - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/io/getFileExtension.js -function getFileExtension(filePath) { - let extension = filePath.slice((filePath.lastIndexOf(".") - 1 >>> 0) + 2); - if (extension.toLowerCase() === "gz") { - const index = filePath.slice(0, -3).lastIndexOf("."); - extension = filePath.slice((index - 1 >>> 0) + 2); - } else if (extension.toLowerCase() === "cbor") { - const index = filePath.slice(0, -5).lastIndexOf("."); - extension = filePath.slice((index - 1 >>> 0) + 2); - } else if (extension.toLowerCase() === "zst") { - const index = filePath.slice(0, -10).lastIndexOf("."); - extension = filePath.slice((index - 1 >>> 0) + 2); - } else if (extension.toLowerCase() === "zip") { - const index = filePath.slice(0, -4).lastIndexOf("."); - extension = filePath.slice((index - 1 >>> 0) + 2); - } - return extension; -} -var getFileExtension_default = getFileExtension; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/internal/imageTransferables.js -function imageTransferables(image) { - return [ - image.data, - image.direction - ]; -} -var imageTransferables_default = imageTransferables; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/internal/meshTransferables.js -function meshTransferables(mesh) { - return [ - mesh.points, - mesh.pointData, - mesh.cells, - mesh.cellData - ]; -} -var meshTransferables_default = meshTransferables; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/internal/loadEmscriptenModuleMainThread.js -async function loadEmscriptenModuleMainThread(moduleRelativePathOrURL, baseUrl) { - let modulePrefix = "unknown"; - if (typeof moduleRelativePathOrURL !== "string") { - modulePrefix = moduleRelativePathOrURL.href; - } else if (moduleRelativePathOrURL.startsWith("http")) { - modulePrefix = moduleRelativePathOrURL; - } else { - modulePrefix = `${baseUrl}/${moduleRelativePathOrURL}`; - } - if (modulePrefix.endsWith(".js")) { - modulePrefix = modulePrefix.substring(0, modulePrefix.length - 3); - } - if (modulePrefix.endsWith(".wasm")) { - modulePrefix = modulePrefix.substring(0, modulePrefix.length - 5); - } - const wasmBinaryPath = `${modulePrefix}.wasm`; - const response = await axios_default.get(wasmBinaryPath, { responseType: "arraybuffer" }); - const wasmBinary = response.data; - const fullModulePath = `${modulePrefix}.js`; - const result = await import( - /* webpackIgnore: true */ - /* @vite-ignore */ - fullModulePath - ); - const instantiated = result.default({ wasmBinary }); - return instantiated; -} -var loadEmscriptenModuleMainThread_default = loadEmscriptenModuleMainThread; - -// node_modules/.pnpm/wasm-feature-detect@1.6.1/node_modules/wasm-feature-detect/dist/esm/index.js -var simd = async () => WebAssembly.validate(new Uint8Array([0, 97, 115, 109, 1, 0, 0, 0, 1, 5, 1, 96, 0, 1, 123, 3, 2, 1, 0, 10, 10, 1, 8, 0, 65, 0, 253, 15, 253, 98, 11])); - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/pipeline/internal/runPipelineEmscripten.js -var haveSharedArrayBuffer2 = typeof globalThis.SharedArrayBuffer === "function"; -var encoder = new TextEncoder(); -var decoder = new TextDecoder("utf-8"); -function readFileSharedArray(emscriptenModule, path) { - const opts = { flags: "r", encoding: "binary" }; - const stream = emscriptenModule.fs_open(path, opts.flags); - const stat = emscriptenModule.fs_stat(path); - const length = stat.size; - let arrayBufferData = null; - if (haveSharedArrayBuffer2) { - arrayBufferData = new SharedArrayBuffer(length); - } else { - arrayBufferData = new ArrayBuffer(length); - } - const array = new Uint8Array(arrayBufferData); - emscriptenModule.fs_read(stream, array, 0, length, 0); - emscriptenModule.fs_close(stream); - return array; -} -function memoryUint8SharedArray(emscriptenModule, byteOffset, length) { - let arrayBufferData = null; - if (haveSharedArrayBuffer2) { - arrayBufferData = new SharedArrayBuffer(length); - } else { - arrayBufferData = new ArrayBuffer(length); - } - const array = new Uint8Array(arrayBufferData); - const dataArrayView = new Uint8Array(emscriptenModule.HEAPU8.buffer, byteOffset, length); - array.set(dataArrayView); - return array; -} -function setPipelineModuleInputArray(emscriptenModule, dataArray, inputIndex, subIndex) { - let dataPtr = 0; - if (dataArray !== null) { - dataPtr = emscriptenModule.ccall("itk_wasm_input_array_alloc", "number", ["number", "number", "number", "number"], [0, inputIndex, subIndex, dataArray.buffer.byteLength]); - emscriptenModule.HEAPU8.set(new Uint8Array(dataArray.buffer), dataPtr); - } - return dataPtr; -} -function setPipelineModuleInputJSON(emscriptenModule, dataObject, inputIndex) { - const dataJSON = JSON.stringify(dataObject); - const jsonPtr = emscriptenModule.ccall("itk_wasm_input_json_alloc", "number", ["number", "number", "number"], [0, inputIndex, dataJSON.length]); - emscriptenModule.writeAsciiToMemory(dataJSON, jsonPtr, false); -} -function getPipelineModuleOutputArray(emscriptenModule, outputIndex, subIndex, componentType) { - const dataPtr = emscriptenModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, outputIndex, subIndex]); - const dataSize = emscriptenModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, outputIndex, subIndex]); - const dataUint8 = memoryUint8SharedArray(emscriptenModule, dataPtr, dataSize); - const data = bufferToTypedArray_default(componentType, dataUint8.buffer); - return data; -} -function getPipelineModuleOutputJSON(emscriptenModule, outputIndex) { - const jsonPtr = emscriptenModule.ccall("itk_wasm_output_json_address", "number", ["number", "number"], [0, outputIndex]); - const dataJSON = emscriptenModule.AsciiToString(jsonPtr); - const dataObject = JSON.parse(dataJSON); - return dataObject; -} -function runPipelineEmscripten(pipelineModule, args, outputs, inputs) { - if (!(inputs == null) && inputs.length > 0) { - inputs.forEach(function(input, index) { - var _a; - switch (input.type) { - case InterfaceTypes_default.TextStream: { - const dataArray = encoder.encode(input.data.data); - const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0); - const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` }; - setPipelineModuleInputJSON(pipelineModule, dataJSON, index); - break; - } - case InterfaceTypes_default.JsonCompatible: { - const dataArray = encoder.encode(JSON.stringify(input.data)); - const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0); - const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` }; - setPipelineModuleInputJSON(pipelineModule, dataJSON, index); - break; - } - case InterfaceTypes_default.BinaryStream: { - const dataArray = input.data.data; - const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0); - const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` }; - setPipelineModuleInputJSON(pipelineModule, dataJSON, index); - break; - } - case InterfaceTypes_default.TextFile: { - pipelineModule.fs_writeFile(input.data.path, input.data.data); - break; - } - case InterfaceTypes_default.BinaryFile: { - pipelineModule.fs_writeFile(input.data.path, input.data.data); - break; - } - case InterfaceTypes_default.Image: { - const image = input.data; - const dataPtr = setPipelineModuleInputArray(pipelineModule, image.data, index, 0); - const directionPtr = setPipelineModuleInputArray(pipelineModule, image.direction, index, 1); - const metadata = typeof ((_a = image.metadata) === null || _a === void 0 ? void 0 : _a.entries) !== "undefined" ? JSON.stringify(Array.from(image.metadata.entries())) : "[]"; - const imageJSON = { - imageType: image.imageType, - name: image.name, - origin: image.origin, - spacing: image.spacing, - direction: `data:application/vnd.itk.address,0:${directionPtr}`, - size: image.size, - data: `data:application/vnd.itk.address,0:${dataPtr}`, - metadata - }; - setPipelineModuleInputJSON(pipelineModule, imageJSON, index); - break; - } - case InterfaceTypes_default.Mesh: { - const mesh = input.data; - const pointsPtr = setPipelineModuleInputArray(pipelineModule, mesh.points, index, 0); - const cellsPtr = setPipelineModuleInputArray(pipelineModule, mesh.cells, index, 1); - const pointDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.pointData, index, 2); - const cellDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.cellData, index, 3); - const meshJSON = { - meshType: mesh.meshType, - name: mesh.name, - numberOfPoints: mesh.numberOfPoints, - points: `data:application/vnd.itk.address,0:${pointsPtr}`, - numberOfCells: mesh.numberOfCells, - cells: `data:application/vnd.itk.address,0:${cellsPtr}`, - cellBufferSize: mesh.cellBufferSize, - numberOfPointPixels: mesh.numberOfPointPixels, - pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`, - numberOfCellPixels: mesh.numberOfCellPixels, - cellData: `data:application/vnd.itk.address,0:${cellDataPtr}` - }; - setPipelineModuleInputJSON(pipelineModule, meshJSON, index); - break; - } - case InterfaceTypes_default.PolyData: { - const polyData = input.data; - const pointsPtr = setPipelineModuleInputArray(pipelineModule, polyData.points, index, 0); - const verticesPtr = setPipelineModuleInputArray(pipelineModule, polyData.vertices, index, 1); - const linesPtr = setPipelineModuleInputArray(pipelineModule, polyData.lines, index, 2); - const polygonsPtr = setPipelineModuleInputArray(pipelineModule, polyData.polygons, index, 3); - const triangleStripsPtr = setPipelineModuleInputArray(pipelineModule, polyData.triangleStrips, index, 4); - const pointDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 5); - const cellDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 6); - const polyDataJSON = { - polyDataType: polyData.polyDataType, - name: polyData.name, - numberOfPoints: polyData.numberOfPoints, - points: `data:application/vnd.itk.address,0:${pointsPtr}`, - verticesBufferSize: polyData.verticesBufferSize, - vertices: `data:application/vnd.itk.address,0:${verticesPtr}`, - linesBufferSize: polyData.linesBufferSize, - lines: `data:application/vnd.itk.address,0:${linesPtr}`, - polygonsBufferSize: polyData.polygonsBufferSize, - polygons: `data:application/vnd.itk.address,0:${polygonsPtr}`, - triangleStripsBufferSize: polyData.triangleStripsBufferSize, - triangleStrips: `data:application/vnd.itk.address,0:${triangleStripsPtr}`, - numberOfPointPixels: polyData.numberOfPointPixels, - pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`, - numberOfCellPixels: polyData.numberOfCellPixels, - cellData: `data:application/vnd.itk.address,0:${cellDataPtr}` - }; - setPipelineModuleInputJSON(pipelineModule, polyDataJSON, index); - break; - } - case IOTypes_default.Text: { - pipelineModule.fs_writeFile(input.path, input.data); - break; - } - case IOTypes_default.Binary: { - pipelineModule.fs_writeFile(input.path, input.data); - break; - } - case IOTypes_default.Image: { - const image = input.data; - const imageJSON = { - imageType: image.imageType, - name: image.name, - origin: image.origin, - spacing: image.spacing, - direction: "data:application/vnd.itk.path,data/direction.raw", - size: image.size, - data: "data:application/vnd.itk.path,data/data.raw" - }; - pipelineModule.fs_mkdirs(`${input.path}/data`); - pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(imageJSON)); - if (image.data === null) { - throw Error("image.data is null"); - } - pipelineModule.fs_writeFile(`${input.path}/data/data.raw`, new Uint8Array(image.data.buffer)); - pipelineModule.fs_writeFile(`${input.path}/data/direction.raw`, new Uint8Array(image.direction.buffer)); - break; - } - case IOTypes_default.Mesh: { - const mesh = input.data; - const meshJSON = { - meshType: mesh.meshType, - name: mesh.name, - numberOfPoints: mesh.numberOfPoints, - points: "data:application/vnd.itk.path,data/points.raw", - numberOfPointPixels: mesh.numberOfPointPixels, - pointData: "data:application/vnd.itk.path,data/pointData.raw", - numberOfCells: mesh.numberOfCells, - cells: "data:application/vnd.itk.path,data/cells.raw", - numberOfCellPixels: mesh.numberOfCellPixels, - cellData: "data:application/vnd.itk.path,data/cellData.raw", - cellBufferSize: mesh.cellBufferSize - }; - pipelineModule.fs_mkdirs(`${input.path}/data`); - pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(meshJSON)); - if (meshJSON.numberOfPoints > 0) { - if (mesh.points === null) { - throw Error("mesh.points is null"); - } - pipelineModule.fs_writeFile(`${input.path}/data/points.raw`, new Uint8Array(mesh.points.buffer)); - } - if (meshJSON.numberOfPointPixels > 0) { - if (mesh.pointData === null) { - throw Error("mesh.pointData is null"); - } - pipelineModule.fs_writeFile(`${input.path}/data/pointData.raw`, new Uint8Array(mesh.pointData.buffer)); - } - if (meshJSON.numberOfCells > 0) { - if (mesh.cells === null) { - throw Error("mesh.cells is null"); - } - pipelineModule.fs_writeFile(`${input.path}/data/cells.raw`, new Uint8Array(mesh.cells.buffer)); - } - if (meshJSON.numberOfCellPixels > 0) { - if (mesh.cellData === null) { - throw Error("mesh.cellData is null"); - } - pipelineModule.fs_writeFile(`${input.path}/data/cellData.raw`, new Uint8Array(mesh.cellData.buffer)); - } - break; - } - default: - throw Error("Unsupported input InterfaceType"); - } - }); - } - pipelineModule.resetModuleStdout(); - pipelineModule.resetModuleStderr(); - const stackPtr = pipelineModule.stackSave(); - let returnValue = 0; - try { - returnValue = pipelineModule.callMain(args.slice()); - } catch (exception) { - if (typeof exception === "number") { - console.log("Exception while running pipeline:"); - console.log("stdout:", pipelineModule.getModuleStdout()); - console.error("stderr:", pipelineModule.getModuleStderr()); - if (typeof pipelineModule.getExceptionMessage !== "undefined") { - console.error("exception:", pipelineModule.getExceptionMessage(exception)); - } else { - console.error("Build module in Debug mode for exception message information."); - } - } - throw exception; - } finally { - pipelineModule.stackRestore(stackPtr); - } - const stdout = pipelineModule.getModuleStdout(); - const stderr = pipelineModule.getModuleStderr(); - const populatedOutputs = []; - if (!(outputs == null) && outputs.length > 0 && returnValue === 0) { - outputs.forEach(function(output, index) { - let outputData = null; - switch (output.type) { - case InterfaceTypes_default.TextStream: { - const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]); - const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]); - const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize); - outputData = { data: decoder.decode(dataArrayView) }; - break; - } - case InterfaceTypes_default.JsonCompatible: { - const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]); - const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]); - const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize); - outputData = JSON.parse(decoder.decode(dataArrayView)); - break; - } - case InterfaceTypes_default.BinaryStream: { - const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]); - const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]); - outputData = { data: memoryUint8SharedArray(pipelineModule, dataPtr, dataSize) }; - break; - } - case InterfaceTypes_default.TextFile: { - outputData = { path: output.data.path, data: pipelineModule.fs_readFile(output.data.path, { encoding: "utf8" }) }; - break; - } - case InterfaceTypes_default.BinaryFile: { - outputData = { path: output.data.path, data: readFileSharedArray(pipelineModule, output.data.path) }; - break; - } - case InterfaceTypes_default.Image: { - const image = getPipelineModuleOutputJSON(pipelineModule, index); - image.data = getPipelineModuleOutputArray(pipelineModule, index, 0, image.imageType.componentType); - image.direction = getPipelineModuleOutputArray(pipelineModule, index, 1, float_types_default.Float64); - image.metadata = new Map(image.metadata); - outputData = image; - break; - } - case InterfaceTypes_default.Mesh: { - const mesh = getPipelineModuleOutputJSON(pipelineModule, index); - if (mesh.numberOfPoints > 0) { - mesh.points = getPipelineModuleOutputArray(pipelineModule, index, 0, mesh.meshType.pointComponentType); - } else { - mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0)); - } - if (mesh.numberOfCells > 0) { - mesh.cells = getPipelineModuleOutputArray(pipelineModule, index, 1, mesh.meshType.cellComponentType); - } else { - mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0)); - } - if (mesh.numberOfPointPixels > 0) { - mesh.pointData = getPipelineModuleOutputArray(pipelineModule, index, 2, mesh.meshType.pointPixelComponentType); - } else { - mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0)); - } - if (mesh.numberOfCellPixels > 0) { - mesh.cellData = getPipelineModuleOutputArray(pipelineModule, index, 3, mesh.meshType.cellPixelComponentType); - } else { - mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0)); - } - outputData = mesh; - break; - } - case InterfaceTypes_default.PolyData: { - const polyData = getPipelineModuleOutputJSON(pipelineModule, index); - if (polyData.numberOfPoints > 0) { - polyData.points = getPipelineModuleOutputArray(pipelineModule, index, 0, float_types_default.Float32); - } else { - polyData.points = new Float32Array(); - } - if (polyData.verticesBufferSize > 0) { - polyData.vertices = getPipelineModuleOutputArray(pipelineModule, index, 1, int_types_default.UInt32); - } else { - polyData.vertices = new Uint32Array(); - } - if (polyData.linesBufferSize > 0) { - polyData.lines = getPipelineModuleOutputArray(pipelineModule, index, 2, int_types_default.UInt32); - } else { - polyData.lines = new Uint32Array(); - } - if (polyData.polygonsBufferSize > 0) { - polyData.polygons = getPipelineModuleOutputArray(pipelineModule, index, 3, int_types_default.UInt32); - } else { - polyData.polygons = new Uint32Array(); - } - if (polyData.triangleStripsBufferSize > 0) { - polyData.triangleStrips = getPipelineModuleOutputArray(pipelineModule, index, 4, int_types_default.UInt32); - } else { - polyData.triangleStrips = new Uint32Array(); - } - if (polyData.numberOfPointPixels > 0) { - polyData.pointData = getPipelineModuleOutputArray(pipelineModule, index, 5, polyData.polyDataType.pointPixelComponentType); - } else { - polyData.pointData = bufferToTypedArray_default(polyData.polyDataType.pointPixelComponentType, new ArrayBuffer(0)); - } - if (polyData.numberOfCellPixels > 0) { - polyData.cellData = getPipelineModuleOutputArray(pipelineModule, index, 6, polyData.polyDataType.cellPixelComponentType); - } else { - polyData.cellData = bufferToTypedArray_default(polyData.polyDataType.cellPixelComponentType, new ArrayBuffer(0)); - } - outputData = polyData; - break; - } - case IOTypes_default.Text: { - if (typeof output.path === "undefined") { - throw new Error("output.path not defined"); - } - outputData = pipelineModule.fs_readFile(output.path, { encoding: "utf8" }); - break; - } - case IOTypes_default.Binary: { - if (typeof output.path === "undefined") { - throw new Error("output.path not defined"); - } - outputData = readFileSharedArray(pipelineModule, output.path); - break; - } - case IOTypes_default.Image: { - if (typeof output.path === "undefined") { - throw new Error("output.path not defined"); - } - const imageJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" }); - const image = JSON.parse(imageJSON); - const dataUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/data.raw`); - image.data = bufferToTypedArray_default(image.imageType.componentType, dataUint8.buffer); - const directionUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/direction.raw`); - image.direction = bufferToTypedArray_default(float_types_default.Float64, directionUint8.buffer); - outputData = image; - break; - } - case IOTypes_default.Mesh: { - if (typeof output.path === "undefined") { - throw new Error("output.path not defined"); - } - const meshJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" }); - const mesh = JSON.parse(meshJSON); - if (mesh.numberOfPoints > 0) { - const dataUint8Points = readFileSharedArray(pipelineModule, `${output.path}/data/points.raw`); - mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, dataUint8Points.buffer); - } else { - mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0)); - } - if (mesh.numberOfPointPixels > 0) { - const dataUint8PointData = readFileSharedArray(pipelineModule, `${output.path}/data/pointData.raw`); - mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, dataUint8PointData.buffer); - } else { - mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0)); - } - if (mesh.numberOfCells > 0) { - const dataUint8Cells = readFileSharedArray(pipelineModule, `${output.path}/data/cells.raw`); - mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, dataUint8Cells.buffer); - } else { - mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0)); - } - if (mesh.numberOfCellPixels > 0) { - const dataUint8CellData = readFileSharedArray(pipelineModule, `${output.path}/data/cellData.raw`); - mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, dataUint8CellData.buffer); - } else { - mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0)); - } - outputData = mesh; - break; - } - default: - throw Error("Unsupported output InterfaceType"); - } - const populatedOutput = { - type: output.type, - data: outputData - }; - populatedOutputs.push(populatedOutput); - }); - } - return { returnValue, stdout, stderr, outputs: populatedOutputs }; -} -var runPipelineEmscripten_default = runPipelineEmscripten; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/pipeline/runPipeline.js -var pipelineToModule = /* @__PURE__ */ new Map(); -async function loadPipelineModule(pipelinePath) { - let moduleRelativePathOrURL = pipelinePath; - let pipeline = pipelinePath; - if (typeof pipelinePath !== "string") { - moduleRelativePathOrURL = new URL(pipelinePath.href); - pipeline = moduleRelativePathOrURL.href; - } - if (pipelineToModule.has(pipeline)) { - return pipelineToModule.get(pipeline); - } else { - const pipelineModule = await loadEmscriptenModuleMainThread_default(pipelinePath, itkConfig_default.pipelinesUrl); - pipelineToModule.set(pipeline, pipelineModule); - return pipelineModule; - } -} -async function runPipeline(webWorker, pipelinePath, args, outputs, inputs, options) { - var _a, _b; - if (!await simd()) { - const simdErrorMessage = "WebAssembly SIMD support is required -- please update your browser."; - alert(simdErrorMessage); - throw new Error(simdErrorMessage); - } - if (webWorker === false) { - const pipelineModule = await loadPipelineModule(pipelinePath.toString()); - const result2 = runPipelineEmscripten_default(pipelineModule, args, outputs, inputs); - return result2; - } - let worker = webWorker; - const pipelineWorkerUrl3 = (_a = options === null || options === void 0 ? void 0 : options.pipelineWorkerUrl) !== null && _a !== void 0 ? _a : null; - const pipelineWorkerUrlString = typeof pipelineWorkerUrl3 !== "string" && typeof (pipelineWorkerUrl3 === null || pipelineWorkerUrl3 === void 0 ? void 0 : pipelineWorkerUrl3.href) !== "undefined" ? pipelineWorkerUrl3.href : pipelineWorkerUrl3; - const { webworkerPromise, worker: usedWorker } = await createWebWorkerPromise_default(worker, pipelineWorkerUrlString); - worker = usedWorker; - const transferables = []; - if (!(inputs == null) && inputs.length > 0) { - inputs.forEach(function(input) { - if (input.type === InterfaceTypes_default.BinaryStream) { - const dataArray = input.data.data; - transferables.push(dataArray); - } else if (input.type === InterfaceTypes_default.BinaryFile) { - const dataArray = input.data.data; - transferables.push(dataArray); - } else if (input.type === InterfaceTypes_default.Image) { - const image = input.data; - if (image.data === null) { - throw Error("image data cannot be null"); - } - transferables.push(...imageTransferables_default(image)); - } else if (input.type === IOTypes_default.Binary) { - transferables.push(input.data); - } else if (input.type === IOTypes_default.Image) { - const image = input.data; - if (image.data === null) { - throw Error("image data cannot be null"); - } - transferables.push(...imageTransferables_default(image)); - } else if (input.type === IOTypes_default.Mesh) { - const mesh = input.data; - transferables.push(...meshTransferables_default(mesh)); - } - }); - } - const pipelineBaseUrl = (_b = options === null || options === void 0 ? void 0 : options.pipelineBaseUrl) !== null && _b !== void 0 ? _b : "pipelinesUrl"; - const pipelineBaseUrlString = typeof pipelineBaseUrl !== "string" && typeof (pipelineBaseUrl === null || pipelineBaseUrl === void 0 ? void 0 : pipelineBaseUrl.href) !== "undefined" ? pipelineBaseUrl.href : pipelineBaseUrl; - const result = await webworkerPromise.postMessage({ - operation: "runPipeline", - config: itkConfig_default, - pipelinePath: pipelinePath.toString(), - pipelineBaseUrl: pipelineBaseUrlString, - args, - outputs, - inputs - }, getTransferables_default(transferables)); - return { - returnValue: result.returnValue, - stdout: result.stdout, - stderr: result.stderr, - outputs: result.outputs, - webWorker: worker - }; -} -var runPipeline_default = runPipeline; - -// package.json -var package_default = { - name: "@itk-wasm/image-io", - version: "0.4.0", - description: "Input and output for scientific and medical image file formats.", - type: "module", - module: "./dist/index.js", - types: "./dist/index.d.ts", - exports: { - ".": { - types: "./dist/index.d.js", - browser: "./dist/index.js", - node: "./dist/index-node.js", - default: "./dist/index.js" - } - }, - scripts: { - start: "npm run copyShoelaceAssets && vite -c build/vite.config.js", - test: "npm run test:node && npm run test:browser", - "test:node": "ava", - "test:browser": "npm run test:browser:chrome && npm run test:browser:firefox", - "test:browser:firefox": "start-server-and-test rollup:start http-get://localhost:5004 cypress:runFirefox", - "test:browser:chrome": "start-server-and-test rollup:start http-get://localhost:5004 cypress:runChrome", - "test:browser:debug": "start-server-and-test rollup:start http-get://localhost:5004 cypress:open", - "cypress:open": "npx cypress open", - "cypress:runChrome": "npx cypress run --browser chrome", - "cypress:runFirefox": "npx cypress run --browser firefox", - build: "npm run build:tsc && npm run build:browser:webWorkers && npm run build:browser:workerEmbedded && npm run build:demo", - "build:browser:webWorkers": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/", - "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/image-io-worker-embedded.js ./src/index-worker-embedded.ts", - "build:tsc": "tsc --pretty", - copyShoelaceAssets: "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", - "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build", - "rollup:start": "npm run copyShoelaceAssets && concurrently npm:rollup:dev npm:rollup:preview", - "rollup:dev": "vite build --config build/vite-rollup-watch.config.ts", - "rollup:preview": "vite preview --config build/vite-rollup-watch.config.ts" - }, - keywords: [ - "itk", - "wasm", - "webassembly", - "wasi" - ], - author: "", - license: "Apache-2.0", - dependencies: { - "itk-wasm": "^1.0.0-b.152" - }, - devDependencies: { - "@shoelace-style/shoelace": "^2.5.2", - "@types/node": "^20.2.5", - ava: "^5.3.1", - concurrently: "^8.2.1", - cypress: "^13.3.0", - esbuild: "^0.19.5", - shx: "^0.3.4", - "start-server-and-test": "^2.0.1", - typescript: "^5.0.4", - vite: "^4.4.11", - "vite-plugin-static-copy": "^0.17.0" - }, - repository: { - type: "git", - url: "https://github.com/InsightSoftwareConsortium/itk-wasm" - }, - ava: { - files: [ - "test/node/**/*", - "!test/node/common.js" - ] - } -}; - -// src/pipelines-base-url.ts -var pipelinesBaseUrl2; -var defaultPipelinesBaseUrl = `https://cdn.jsdelivr.net/npm/@itk-wasm/image-io@${package_default.version}/dist/pipelines`; -function setPipelinesBaseUrl(baseUrl) { - pipelinesBaseUrl2 = baseUrl; -} -function getPipelinesBaseUrl2() { - if (typeof pipelinesBaseUrl2 !== "undefined") { - return pipelinesBaseUrl2; - } - const itkWasmPipelinesBaseUrl = getPipelinesBaseUrl(); - if (typeof itkWasmPipelinesBaseUrl !== "undefined") { - return itkWasmPipelinesBaseUrl; - } - return defaultPipelinesBaseUrl; -} - -// src/pipeline-worker-url.ts -var pipelineWorkerUrl2; -var defaultPipelineWorkerUrl = null; -function setPipelineWorkerUrl(workerUrl) { - pipelineWorkerUrl2 = workerUrl; -} -function getPipelineWorkerUrl2() { - if (typeof pipelineWorkerUrl2 !== "undefined") { - return pipelineWorkerUrl2; - } - const itkWasmPipelineWorkerUrl = getPipelineWorkerUrl(); - if (typeof itkWasmPipelineWorkerUrl !== "undefined") { - return itkWasmPipelineWorkerUrl; - } - return defaultPipelineWorkerUrl; -} - -// src/mime-to-image-io.ts -var mimeToImageIo = /* @__PURE__ */ new Map([ - ["image/jpeg", "jpeg"], - ["image/png", "png"], - ["image/tiff", "tiff"], - ["image/x-ms-bmp", "bmp"], - ["image/x-bmp", "bmp"], - ["image/bmp", "bmp"], - ["application/dicom", "gdcm"] -]); -var mime_to_image_io_default = mimeToImageIo; - -// src/extension-to-image-io.ts -var extensionToImageIo = /* @__PURE__ */ new Map([ - ["bmp", "bmp"], - ["dcm", "gdcm"], - ["gipl", "gipl"], - ["gipl.gz", "gipl"], - ["hdf5", "hdf5"], - ["jpg", "jpeg"], - ["jpeg", "jpeg"], - ["iwi", "wasm"], - ["iwi.cbor", "wasm"], - ["iwi.cbor.zst", "wasmZstd"], - ["lsm", "lsm"], - ["mnc", "mnc"], - ["mnc.gz", "mnc"], - ["mnc2", "mnc"], - ["mgh", "mgh"], - ["mgz", "mgh"], - ["mgh.gz", "mgh"], - ["mha", "meta"], - ["mhd", "meta"], - ["mrc", "mrc"], - ["nia", "nifti"], - ["nii", "nifti"], - ["nii.gz", "nifti"], - ["hdr", "nifti"], - ["nrrd", "nrrd"], - ["nhdr", "nrrd"], - ["png", "png"], - ["pic", "bioRad"], - ["tif", "tiff"], - ["tiff", "tiff"], - ["vtk", "vtk"], - ["isq", "scanco"], - ["aim", "scanco"], - ["fdf", "fdf"] -]); -var extension_to_image_io_default = extensionToImageIo; - -// src/png-read-image.ts -async function pngReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "png-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var png_read_image_default = pngReadImage; - -// src/png-write-image.ts -async function pngWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "png-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var png_write_image_default = pngWriteImage; - -// src/meta-read-image.ts -async function metaReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "meta-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var meta_read_image_default = metaReadImage; - -// src/meta-write-image.ts -async function metaWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "meta-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var meta_write_image_default = metaWriteImage; - -// src/tiff-read-image.ts -async function tiffReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "tiff-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var tiff_read_image_default = tiffReadImage; - -// src/tiff-write-image.ts -async function tiffWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "tiff-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var tiff_write_image_default = tiffWriteImage; - -// src/nifti-read-image.ts -async function niftiReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "nifti-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var nifti_read_image_default = niftiReadImage; - -// src/nifti-write-image.ts -async function niftiWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "nifti-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var nifti_write_image_default = niftiWriteImage; - -// src/jpeg-read-image.ts -async function jpegReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "jpeg-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var jpeg_read_image_default = jpegReadImage; - -// src/jpeg-write-image.ts -async function jpegWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "jpeg-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var jpeg_write_image_default = jpegWriteImage; - -// src/nrrd-read-image.ts -async function nrrdReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "nrrd-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var nrrd_read_image_default = nrrdReadImage; - -// src/nrrd-write-image.ts -async function nrrdWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "nrrd-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var nrrd_write_image_default = nrrdWriteImage; - -// src/vtk-read-image.ts -async function vtkReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "vtk-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var vtk_read_image_default = vtkReadImage; - -// src/vtk-write-image.ts -async function vtkWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "vtk-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var vtk_write_image_default = vtkWriteImage; - -// src/bmp-read-image.ts -async function bmpReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "bmp-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var bmp_read_image_default = bmpReadImage; - -// src/bmp-write-image.ts -async function bmpWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "bmp-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var bmp_write_image_default = bmpWriteImage; - -// src/hdf5-read-image.ts -async function hdf5ReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "hdf5-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var hdf5_read_image_default = hdf5ReadImage; - -// src/hdf5-write-image.ts -async function hdf5WriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "hdf5-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var hdf5_write_image_default = hdf5WriteImage; - -// src/minc-read-image.ts -async function mincReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "minc-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var minc_read_image_default = mincReadImage; - -// src/minc-write-image.ts -async function mincWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "minc-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var minc_write_image_default = mincWriteImage; - -// src/mrc-read-image.ts -async function mrcReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "mrc-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var mrc_read_image_default = mrcReadImage; - -// src/mrc-write-image.ts -async function mrcWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "mrc-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var mrc_write_image_default = mrcWriteImage; - -// src/lsm-read-image.ts -async function lsmReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "lsm-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var lsm_read_image_default = lsmReadImage; - -// src/lsm-write-image.ts -async function lsmWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "lsm-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var lsm_write_image_default = lsmWriteImage; - -// src/mgh-read-image.ts -async function mghReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "mgh-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var mgh_read_image_default = mghReadImage; - -// src/mgh-write-image.ts -async function mghWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "mgh-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var mgh_write_image_default = mghWriteImage; - -// src/bio-rad-read-image.ts -async function bioRadReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "bio-rad-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var bio_rad_read_image_default = bioRadReadImage; - -// src/bio-rad-write-image.ts -async function bioRadWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "bio-rad-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var bio_rad_write_image_default = bioRadWriteImage; - -// src/gipl-read-image.ts -async function giplReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "gipl-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var gipl_read_image_default = giplReadImage; - -// src/gipl-write-image.ts -async function giplWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "gipl-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var gipl_write_image_default = giplWriteImage; - -// src/ge-adw-read-image.ts -async function geAdwReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "ge-adw-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var ge_adw_read_image_default = geAdwReadImage; - -// src/ge-adw-write-image.ts -async function geAdwWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "ge-adw-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var ge_adw_write_image_default = geAdwWriteImage; - -// src/ge4-read-image.ts -async function ge4ReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "ge4-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var ge4_read_image_default = ge4ReadImage; - -// src/ge4-write-image.ts -async function ge4WriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "ge4-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var ge4_write_image_default = ge4WriteImage; - -// src/ge5-read-image.ts -async function ge5ReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "ge5-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var ge5_read_image_default = ge5ReadImage; - -// src/ge5-write-image.ts -async function ge5WriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "ge5-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var ge5_write_image_default = ge5WriteImage; - -// src/gdcm-read-image.ts -async function gdcmReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "gdcm-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var gdcm_read_image_default = gdcmReadImage; - -// src/gdcm-write-image.ts -async function gdcmWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "gdcm-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var gdcm_write_image_default = gdcmWriteImage; - -// src/scanco-read-image.ts -async function scancoReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "scanco-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var scanco_read_image_default = scancoReadImage; - -// src/scanco-write-image.ts -async function scancoWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "scanco-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var scanco_write_image_default = scancoWriteImage; - -// src/fdf-read-image.ts -async function fdfReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "fdf-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var fdf_read_image_default = fdfReadImage; - -// src/wasm-read-image.ts -async function wasmReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "wasm-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var wasm_read_image_default = wasmReadImage; - -// src/wasm-write-image.ts -async function wasmWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "wasm-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var wasm_write_image_default = wasmWriteImage; - -// src/wasm-zstd-read-image.ts -async function wasmZstdReadImage(webWorker, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.Image } - ]; - let serializedImageFile = serializedImage; - if (serializedImage instanceof File) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - const inputs = [ - { type: InterfaceTypes_default.BinaryFile, data: serializedImageFile } - ]; - const args = []; - const serializedImageName = serializedImageFile.path; - args.push(serializedImageName); - const couldReadName = "0"; - args.push(couldReadName); - const imageName = "1"; - args.push(imageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - const pipelinePath = "wasm-zstd-read-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldRead: outputs[0]?.data, - image: outputs[1]?.data - }; - return result; -} -var wasm_zstd_read_image_default = wasmZstdReadImage; - -// src/wasm-zstd-write-image.ts -async function wasmZstdWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "wasm-zstd-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var wasm_zstd_write_image_default = wasmZstdWriteImage; - -// src/image-io-index.ts -var imageIoIndex = /* @__PURE__ */ new Map([ - ["png", [png_read_image_default, png_write_image_default]], - ["meta", [meta_read_image_default, meta_write_image_default]], - ["tiff", [tiff_read_image_default, tiff_write_image_default]], - ["nifti", [nifti_read_image_default, nifti_write_image_default]], - ["jpeg", [jpeg_read_image_default, jpeg_write_image_default]], - ["nrrd", [nrrd_read_image_default, nrrd_write_image_default]], - ["vtk", [vtk_read_image_default, vtk_write_image_default]], - ["bmp", [bmp_read_image_default, bmp_write_image_default]], - ["hdf5", [hdf5_read_image_default, hdf5_write_image_default]], - ["minc", [minc_read_image_default, minc_write_image_default]], - ["mrc", [mrc_read_image_default, mrc_write_image_default]], - ["lsm", [lsm_read_image_default, lsm_write_image_default]], - ["mgh", [mgh_read_image_default, mgh_write_image_default]], - ["bioRad", [bio_rad_read_image_default, bio_rad_write_image_default]], - ["gipl", [gipl_read_image_default, gipl_write_image_default]], - ["geAdw", [ge_adw_read_image_default, ge_adw_write_image_default]], - ["ge4", [ge4_read_image_default, ge4_write_image_default]], - ["ge5", [ge5_read_image_default, ge5_write_image_default]], - ["gdcm", [gdcm_read_image_default, gdcm_write_image_default]], - ["scanco", [scanco_read_image_default, scanco_write_image_default]], - ["fdf", [fdf_read_image_default, null]], - ["wasm", [wasm_read_image_default, wasm_write_image_default]], - ["wasmZstd", [wasm_zstd_read_image_default, wasm_zstd_write_image_default]] -]); -var image_io_index_default = imageIoIndex; - -// src/read-image.ts -async function readImage(webWorker, serializedImage, options = {}) { - const mimeType = serializedImage.type ?? ""; - const fileName = serializedImage.name ?? serializedImage.path ?? "fileName"; - const extension = getFileExtension_default(fileName).toLowerCase(); - let usedWebWorker = webWorker; - let serializedImageFile = serializedImage; - if (serializedImage instanceof Blob) { - const serializedImageBuffer = await serializedImage.arrayBuffer(); - serializedImageFile = { path: serializedImage.name, data: new Uint8Array(serializedImageBuffer) }; - } - let io = null; - if (mimeType && mime_to_image_io_default.has(mimeType)) { - io = mime_to_image_io_default.get(mimeType); - } else if (extension_to_image_io_default.has(extension)) { - io = extension_to_image_io_default.get(extension); - } else { - for (const readerWriter2 of image_io_index_default.values()) { - if (readerWriter2[0] !== null) { - let { webWorker: testWebWorker2, couldRead: couldRead2, image: image2 } = await readerWriter2[0](usedWebWorker, { path: serializedImageFile.path, data: serializedImageFile.data.slice() }, { informationOnly: options.informationOnly }); - usedWebWorker = testWebWorker2; - if (couldRead2) { - if (typeof options !== "undefined") { - image2 = castImage_default(image2, options); - } - return { webWorker: usedWebWorker, image: image2 }; - } - } - } - } - if (!io) { - throw Error("Could not find IO for: " + fileName); - } - const readerWriter = image_io_index_default.get(io); - const reader = readerWriter[0]; - let { webWorker: testWebWorker, couldRead, image } = await reader(usedWebWorker, serializedImageFile, { informationOnly: options.informationOnly }); - usedWebWorker = testWebWorker; - if (!couldRead) { - throw Error("Could not read: " + fileName); - } - if (typeof options !== "undefined") { - image = castImage_default(image, options); - } - return { webWorker: usedWebWorker, image }; -} -var read_image_default = readImage; - -// src/read-image-file-series.ts -var numberOfWorkers = typeof globalThis.navigator?.hardwareConcurrency === "number" ? globalThis.navigator.hardwareConcurrency : 6; -var workerPool = new WorkerPool_default(numberOfWorkers, read_image_default); -async function readImageFileSeries(fileList, options) { - let zSpacing = 1; - let zOrigin = 0; - let sortedSeries = false; - if (typeof options === "object") { - if (typeof options.zSpacing !== "undefined") { - zSpacing = options.zSpacing; - } - if (typeof options.zOrigin !== "undefined") { - zOrigin = options.zOrigin; - } - if (typeof options.sortedSeries !== "undefined") { - sortedSeries = options.sortedSeries; - } - } - const fetchFileDescriptions = Array.from(fileList, async function(file) { - return await file.arrayBuffer().then(function(arrayBuffer) { - const fileDescription = { - name: file.name, - type: file.type, - data: arrayBuffer - }; - return fileDescription; - }); - }); - const fileDescriptions = await Promise.all(fetchFileDescriptions); - if (!sortedSeries) { - fileDescriptions.sort((a, b) => { - if (a.name < b.name) { - return -1; - } - if (a.name > b.name) { - return 1; - } - return 0; - }); - } - const taskArgsArray = []; - for (let index = 0; index < fileDescriptions.length; index++) { - taskArgsArray.push([fileDescriptions[index].data, fileDescriptions[index].name]); - } - const results = await workerPool.runTasks(taskArgsArray).promise; - const images = results.map((result) => { - const image = result.image; - image.imageType.dimension = 3; - image.size.push(1); - image.spacing.push(zSpacing); - image.origin.push(zOrigin); - image.direction = new Float64Array(9); - image.direction.fill(0); - image.direction[0] = 1; - image.direction[4] = 1; - image.direction[8] = 1; - return image; - }); - let stacked = stackImages_default(images); - if (typeof options === "object" && (typeof options.componentType !== "undefined" || typeof options.pixelType !== "undefined")) { - stacked = castImage_default(stacked, options); - } - return { image: stacked, webWorkerPool: workerPool }; -} -var read_image_file_series_default = readImageFileSeries; - -// src/write-image.ts -async function writeImage(webWorker, image, serializedImage, options = {}) { - let inputImage = image; - if (typeof options.componentType !== "undefined" || typeof options.pixelType !== "undefined") { - inputImage = castImage_default(image, options); - } - const mimeType = options.mimeType; - const extension = getFileExtension_default(serializedImage).toLowerCase(); - let usedWebWorker = webWorker; - let io = null; - if (typeof mimeType !== "undefined" && mime_to_image_io_default.has(mimeType)) { - io = mime_to_image_io_default.get(mimeType); - } else if (extension_to_image_io_default.has(extension)) { - io = extension_to_image_io_default.get(extension); - } else { - for (const readerWriter2 of image_io_index_default.values()) { - if (readerWriter2[1] !== null) { - let { webWorker: testWebWorker2, couldWrite: couldWrite2, serializedImage: serializedImageBuffer2 } = await readerWriter2[1](usedWebWorker, copyImage_default(inputImage), serializedImage, options); - usedWebWorker = testWebWorker2; - if (couldWrite2) { - return { webWorker: usedWebWorker, serializedImage: serializedImageBuffer2 }; - } - } - } - } - if (!io) { - throw Error("Could not find IO for: " + serializedImage); - } - const readerWriter = image_io_index_default.get(io); - const writer = readerWriter[1]; - let { webWorker: testWebWorker, couldWrite, serializedImage: serializedImageBuffer } = await writer(usedWebWorker, inputImage, serializedImage, options); - usedWebWorker = testWebWorker; - if (!couldWrite) { - throw Error("Could not write: " + serializedImage); - } - const result = { - webWorker: usedWebWorker, - serializedImage: serializedImageBuffer - }; - return result; -} -var write_image_default = writeImage; - -// src/fdf-write-image.ts -async function fdfWriteImage(webWorker, image, serializedImage, options = {}) { - const desiredOutputs = [ - { type: InterfaceTypes_default.JsonCompatible }, - { type: InterfaceTypes_default.BinaryFile, data: { path: serializedImage, data: new Uint8Array() } } - ]; - const inputs = [ - { type: InterfaceTypes_default.Image, data: image } - ]; - const args = []; - const imageName = "0"; - args.push(imageName); - const couldWriteName = "0"; - args.push(couldWriteName); - const serializedImageName = serializedImage; - args.push(serializedImageName); - args.push("--memory-io"); - if (typeof options.informationOnly !== "undefined") { - options.informationOnly && args.push("--information-only"); - } - if (typeof options.useCompression !== "undefined") { - options.useCompression && args.push("--use-compression"); - } - const pipelinePath = "fdf-write-image"; - const { - webWorker: usedWebWorker, - returnValue, - stderr, - outputs - } = await runPipeline_default(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl2(), pipelineWorkerUrl: getPipelineWorkerUrl2() }); - if (returnValue !== 0 && stderr !== "") { - throw new Error(stderr); - } - const result = { - webWorker: usedWebWorker, - couldWrite: outputs[0]?.data, - serializedImage: outputs[1]?.data - }; - return result; -} -var fdf_write_image_default = fdfWriteImage; - -// node_modules/.pnpm/itk-wasm@1.0.0-b.152/node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js -var itk_wasm_pipeline_worker_default = 'data:text/javascript;charset=utf-8,var __create = Object.create;%0Avar __defProp = Object.defineProperty;%0Avar __getOwnPropDesc = Object.getOwnPropertyDescriptor;%0Avar __getOwnPropNames = Object.getOwnPropertyNames;%0Avar __getProtoOf = Object.getPrototypeOf;%0Avar __hasOwnProp = Object.prototype.hasOwnProperty;%0Avar __commonJS = (cb, mod) => function __require() {%0A return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;%0A};%0Avar __copyProps = (to, from, except, desc) => {%0A if (from && typeof from === "object" || typeof from === "function") {%0A for (let key of __getOwnPropNames(from))%0A if (!__hasOwnProp.call(to, key) && key !== except)%0A __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });%0A }%0A return to;%0A};%0Avar __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(%0A // If the importer is in node compatibility mode or this is not an ESM%0A // file that has been converted to a CommonJS file using a Babel-%0A // compatible transform (i.e. "__esModule" has not been set), then set%0A // "default" to the CommonJS "module.exports" for node compatibility.%0A isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,%0A mod%0A));%0A%0A// node_modules/webworker-promise/lib/tiny-emitter.js%0Avar require_tiny_emitter = __commonJS({%0A "node_modules/webworker-promise/lib/tiny-emitter.js"(exports, module) {%0A "use strict";%0A var _createClass = function() {%0A function defineProperties(target, props) {%0A for (var i = 0; i < props.length; i++) {%0A var descriptor = props[i];%0A descriptor.enumerable = descriptor.enumerable || false;%0A descriptor.configurable = true;%0A if ("value" in descriptor)%0A descriptor.writable = true;%0A Object.defineProperty(target, descriptor.key, descriptor);%0A }%0A }%0A return function(Constructor, protoProps, staticProps) {%0A if (protoProps)%0A defineProperties(Constructor.prototype, protoProps);%0A if (staticProps)%0A defineProperties(Constructor, staticProps);%0A return Constructor;%0A };%0A }();%0A function _classCallCheck(instance2, Constructor) {%0A if (!(instance2 instanceof Constructor)) {%0A throw new TypeError("Cannot call a class as a function");%0A }%0A }%0A var TinyEmitter = function() {%0A function TinyEmitter2() {%0A _classCallCheck(this, TinyEmitter2);%0A Object.defineProperty(this, "__listeners", {%0A value: {},%0A enumerable: false,%0A writable: false%0A });%0A }%0A _createClass(TinyEmitter2, [{%0A key: "emit",%0A value: function emit(eventName) {%0A if (!this.__listeners[eventName])%0A return this;%0A for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {%0A args[_key - 1] = arguments[_key];%0A }%0A var _iteratorNormalCompletion = true;%0A var _didIteratorError = false;%0A var _iteratorError = void 0;%0A try {%0A for (var _iterator = this.__listeners[eventName][Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {%0A var handler = _step.value;%0A handler.apply(void 0, args);%0A }%0A } catch (err) {%0A _didIteratorError = true;%0A _iteratorError = err;%0A } finally {%0A try {%0A if (!_iteratorNormalCompletion && _iterator.return) {%0A _iterator.return();%0A }%0A } finally {%0A if (_didIteratorError) {%0A throw _iteratorError;%0A }%0A }%0A }%0A return this;%0A }%0A }, {%0A key: "once",%0A value: function once(eventName, handler) {%0A var _this = this;%0A var once2 = function once3() {%0A _this.off(eventName, once3);%0A handler.apply(void 0, arguments);%0A };%0A return this.on(eventName, once2);%0A }%0A }, {%0A key: "on",%0A value: function on(eventName, handler) {%0A if (!this.__listeners[eventName])%0A this.__listeners[eventName] = [];%0A this.__listeners[eventName].push(handler);%0A return this;%0A }%0A }, {%0A key: "off",%0A value: function off(eventName, handler) {%0A if (handler)%0A this.__listeners[eventName] = this.__listeners[eventName].filter(function(h) {%0A return h !== handler;%0A });%0A else%0A this.__listeners[eventName] = [];%0A return this;%0A }%0A }]);%0A return TinyEmitter2;%0A }();%0A module.exports = TinyEmitter;%0A }%0A});%0A%0A// node_modules/webworker-promise/lib/register.js%0Avar require_register = __commonJS({%0A "node_modules/webworker-promise/lib/register.js"(exports, module) {%0A "use strict";%0A var _createClass = function() {%0A function defineProperties(target, props) {%0A for (var i = 0; i < props.length; i++) {%0A var descriptor = props[i];%0A descriptor.enumerable = descriptor.enumerable || false;%0A descriptor.configurable = true;%0A if ("value" in descriptor)%0A descriptor.writable = true;%0A Object.defineProperty(target, descriptor.key, descriptor);%0A }%0A }%0A return function(Constructor, protoProps, staticProps) {%0A if (protoProps)%0A defineProperties(Constructor.prototype, protoProps);%0A if (staticProps)%0A defineProperties(Constructor, staticProps);%0A return Constructor;%0A };%0A }();%0A var _get = function get(object, property, receiver) {%0A if (object === null)%0A object = Function.prototype;%0A var desc = Object.getOwnPropertyDescriptor(object, property);%0A if (desc === void 0) {%0A var parent = Object.getPrototypeOf(object);%0A if (parent === null) {%0A return void 0;%0A } else {%0A return get(parent, property, receiver);%0A }%0A } else if ("value" in desc) {%0A return desc.value;%0A } else {%0A var getter = desc.get;%0A if (getter === void 0) {%0A return void 0;%0A }%0A return getter.call(receiver);%0A }%0A };%0A var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function(obj) {%0A return typeof obj;%0A } : function(obj) {%0A return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;%0A };%0A function _toConsumableArray(arr) {%0A if (Array.isArray(arr)) {%0A for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) {%0A arr2[i] = arr[i];%0A }%0A return arr2;%0A } else {%0A return Array.from(arr);%0A }%0A }%0A function _classCallCheck(instance2, Constructor) {%0A if (!(instance2 instanceof Constructor)) {%0A throw new TypeError("Cannot call a class as a function");%0A }%0A }%0A function _possibleConstructorReturn(self2, call) {%0A if (!self2) {%0A throw new ReferenceError("this hasn\'t been initialised - super() hasn\'t been called");%0A }%0A return call && (typeof call === "object" || typeof call === "function") ? call : self2;%0A }%0A function _inherits(subClass, superClass) {%0A if (typeof superClass !== "function" && superClass !== null) {%0A throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);%0A }%0A subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } });%0A if (superClass)%0A Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;%0A }%0A function _defineProperty(obj, key, value) {%0A if (key in obj) {%0A Object.defineProperty(obj, key, { value, enumerable: true, configurable: true, writable: true });%0A } else {%0A obj[key] = value;%0A }%0A return obj;%0A }%0A var TinyEmitter = require_tiny_emitter();%0A var MESSAGE_RESULT = 0;%0A var MESSAGE_EVENT = 1;%0A var RESULT_ERROR = 0;%0A var RESULT_SUCCESS = 1;%0A var DEFAULT_HANDLER = "main";%0A var isPromise = function isPromise2(o) {%0A return (typeof o === "undefined" ? "undefined" : _typeof(o)) === "object" && o !== null && typeof o.then === "function" && typeof o.catch === "function";%0A };%0A function RegisterPromise(fn) {%0A var handlers = _defineProperty({}, DEFAULT_HANDLER, fn);%0A var sendPostMessage = self.postMessage.bind(self);%0A var server = new (function(_TinyEmitter) {%0A _inherits(WorkerRegister, _TinyEmitter);%0A function WorkerRegister() {%0A _classCallCheck(this, WorkerRegister);%0A return _possibleConstructorReturn(this, (WorkerRegister.__proto__ || Object.getPrototypeOf(WorkerRegister)).apply(this, arguments));%0A }%0A _createClass(WorkerRegister, [{%0A key: "emit",%0A value: function emit(eventName) {%0A for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {%0A args[_key - 1] = arguments[_key];%0A }%0A if (args.length == 1 && args[0] instanceof TransferableResponse) {%0A sendPostMessage({ eventName, args }, args[0].transferable);%0A } else {%0A sendPostMessage({ eventName, args });%0A }%0A return this;%0A }%0A }, {%0A key: "emitLocally",%0A value: function emitLocally(eventName) {%0A var _get2;%0A for (var _len2 = arguments.length, args = Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {%0A args[_key2 - 1] = arguments[_key2];%0A }%0A (_get2 = _get(WorkerRegister.prototype.__proto__ || Object.getPrototypeOf(WorkerRegister.prototype), "emit", this)).call.apply(_get2, [this, eventName].concat(args));%0A }%0A }, {%0A key: "operation",%0A value: function operation(name, handler) {%0A handlers[name] = handler;%0A return this;%0A }%0A }]);%0A return WorkerRegister;%0A }(TinyEmitter))();%0A var run = function run2(messageId, payload, handlerName) {%0A var onSuccess = function onSuccess2(result2) {%0A if (result2 && result2 instanceof TransferableResponse) {%0A sendResult(messageId, RESULT_SUCCESS, result2.payload, result2.transferable);%0A } else {%0A sendResult(messageId, RESULT_SUCCESS, result2);%0A }%0A };%0A var onError = function onError2(e) {%0A sendResult(messageId, RESULT_ERROR, {%0A message: e.message,%0A stack: e.stack%0A });%0A };%0A try {%0A var result = runFn(messageId, payload, handlerName);%0A if (isPromise(result)) {%0A result.then(onSuccess).catch(onError);%0A } else {%0A onSuccess(result);%0A }%0A } catch (e) {%0A onError(e);%0A }%0A };%0A var runFn = function runFn2(messageId, payload, handlerName) {%0A var handler = handlers[handlerName || DEFAULT_HANDLER];%0A if (!handler)%0A throw new Error("Not found handler for this request");%0A return handler(payload, sendEvent.bind(null, messageId));%0A };%0A var sendResult = function sendResult2(messageId, success, payload) {%0A var transferable = arguments.length > 3 && arguments[3] !== void 0 ? arguments[3] : [];%0A sendPostMessage([MESSAGE_RESULT, messageId, success, payload], transferable);%0A };%0A var sendEvent = function sendEvent2(messageId, eventName, payload) {%0A if (!eventName)%0A throw new Error("eventName is required");%0A if (typeof eventName !== "string")%0A throw new Error("eventName should be string");%0A sendPostMessage([MESSAGE_EVENT, messageId, eventName, payload]);%0A };%0A self.addEventListener("message", function(_ref) {%0A var data = _ref.data;%0A if (Array.isArray(data)) {%0A run.apply(void 0, _toConsumableArray(data));%0A } else if (data && data.eventName) {%0A server.emitLocally.apply(server, [data.eventName].concat(_toConsumableArray(data.args)));%0A }%0A });%0A return server;%0A }%0A var TransferableResponse = function TransferableResponse2(payload, transferable) {%0A _classCallCheck(this, TransferableResponse2);%0A this.payload = payload;%0A this.transferable = transferable;%0A };%0A module.exports = RegisterPromise;%0A module.exports.TransferableResponse = TransferableResponse;%0A }%0A});%0A%0A// dist/core/web-workers/itk-wasm-pipeline.worker.js%0Avar import_register2 = __toESM(require_register(), 1);%0A%0A// node_modules/axios/lib/helpers/bind.js%0Afunction bind(fn, thisArg) {%0A return function wrap() {%0A return fn.apply(thisArg, arguments);%0A };%0A}%0A%0A// node_modules/axios/lib/utils.js%0Avar { toString } = Object.prototype;%0Avar { getPrototypeOf } = Object;%0Avar kindOf = ((cache) => (thing) => {%0A const str = toString.call(thing);%0A return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());%0A})(/* @__PURE__ */ Object.create(null));%0Avar kindOfTest = (type) => {%0A type = type.toLowerCase();%0A return (thing) => kindOf(thing) === type;%0A};%0Avar typeOfTest = (type) => (thing) => typeof thing === type;%0Avar { isArray } = Array;%0Avar isUndefined = typeOfTest("undefined");%0Afunction isBuffer(val) {%0A return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor) && isFunction(val.constructor.isBuffer) && val.constructor.isBuffer(val);%0A}%0Avar isArrayBuffer = kindOfTest("ArrayBuffer");%0Afunction isArrayBufferView(val) {%0A let result;%0A if (typeof ArrayBuffer !== "undefined" && ArrayBuffer.isView) {%0A result = ArrayBuffer.isView(val);%0A } else {%0A result = val && val.buffer && isArrayBuffer(val.buffer);%0A }%0A return result;%0A}%0Avar isString = typeOfTest("string");%0Avar isFunction = typeOfTest("function");%0Avar isNumber = typeOfTest("number");%0Avar isObject = (thing) => thing !== null && typeof thing === "object";%0Avar isBoolean = (thing) => thing === true || thing === false;%0Avar isPlainObject = (val) => {%0A if (kindOf(val) !== "object") {%0A return false;%0A }%0A const prototype3 = getPrototypeOf(val);%0A return (prototype3 === null || prototype3 === Object.prototype || Object.getPrototypeOf(prototype3) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val);%0A};%0Avar isDate = kindOfTest("Date");%0Avar isFile = kindOfTest("File");%0Avar isBlob = kindOfTest("Blob");%0Avar isFileList = kindOfTest("FileList");%0Avar isStream = (val) => isObject(val) && isFunction(val.pipe);%0Avar isFormData = (thing) => {%0A let kind;%0A return thing && (typeof FormData === "function" && thing instanceof FormData || isFunction(thing.append) && ((kind = kindOf(thing)) === "formdata" || // detect form-data instance%0A kind === "object" && isFunction(thing.toString) && thing.toString() === "[object FormData]"));%0A};%0Avar isURLSearchParams = kindOfTest("URLSearchParams");%0Avar trim = (str) => str.trim ? str.trim() : str.replace(/^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, "");%0Afunction forEach(obj, fn, { allOwnKeys = false } = {}) {%0A if (obj === null || typeof obj === "undefined") {%0A return;%0A }%0A let i;%0A let l;%0A if (typeof obj !== "object") {%0A obj = [obj];%0A }%0A if (isArray(obj)) {%0A for (i = 0, l = obj.length; i < l; i++) {%0A fn.call(null, obj[i], i, obj);%0A }%0A } else {%0A const keys = allOwnKeys ? Object.getOwnPropertyNames(obj) : Object.keys(obj);%0A const len = keys.length;%0A let key;%0A for (i = 0; i < len; i++) {%0A key = keys[i];%0A fn.call(null, obj[key], key, obj);%0A }%0A }%0A}%0Afunction findKey(obj, key) {%0A key = key.toLowerCase();%0A const keys = Object.keys(obj);%0A let i = keys.length;%0A let _key;%0A while (i-- > 0) {%0A _key = keys[i];%0A if (key === _key.toLowerCase()) {%0A return _key;%0A }%0A }%0A return null;%0A}%0Avar _global = (() => {%0A if (typeof globalThis !== "undefined")%0A return globalThis;%0A return typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : global;%0A})();%0Avar isContextDefined = (context) => !isUndefined(context) && context !== _global;%0Afunction merge() {%0A const { caseless } = isContextDefined(this) && this || {};%0A const result = {};%0A const assignValue = (val, key) => {%0A const targetKey = caseless && findKey(result, key) || key;%0A if (isPlainObject(result[targetKey]) && isPlainObject(val)) {%0A result[targetKey] = merge(result[targetKey], val);%0A } else if (isPlainObject(val)) {%0A result[targetKey] = merge({}, val);%0A } else if (isArray(val)) {%0A result[targetKey] = val.slice();%0A } else {%0A result[targetKey] = val;%0A }%0A };%0A for (let i = 0, l = arguments.length; i < l; i++) {%0A arguments[i] && forEach(arguments[i], assignValue);%0A }%0A return result;%0A}%0Avar extend = (a, b, thisArg, { allOwnKeys } = {}) => {%0A forEach(b, (val, key) => {%0A if (thisArg && isFunction(val)) {%0A a[key] = bind(val, thisArg);%0A } else {%0A a[key] = val;%0A }%0A }, { allOwnKeys });%0A return a;%0A};%0Avar stripBOM = (content) => {%0A if (content.charCodeAt(0) === 65279) {%0A content = content.slice(1);%0A }%0A return content;%0A};%0Avar inherits = (constructor, superConstructor, props, descriptors2) => {%0A constructor.prototype = Object.create(superConstructor.prototype, descriptors2);%0A constructor.prototype.constructor = constructor;%0A Object.defineProperty(constructor, "super", {%0A value: superConstructor.prototype%0A });%0A props && Object.assign(constructor.prototype, props);%0A};%0Avar toFlatObject = (sourceObj, destObj, filter2, propFilter) => {%0A let props;%0A let i;%0A let prop;%0A const merged = {};%0A destObj = destObj || {};%0A if (sourceObj == null)%0A return destObj;%0A do {%0A props = Object.getOwnPropertyNames(sourceObj);%0A i = props.length;%0A while (i-- > 0) {%0A prop = props[i];%0A if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {%0A destObj[prop] = sourceObj[prop];%0A merged[prop] = true;%0A }%0A }%0A sourceObj = filter2 !== false && getPrototypeOf(sourceObj);%0A } while (sourceObj && (!filter2 || filter2(sourceObj, destObj)) && sourceObj !== Object.prototype);%0A return destObj;%0A};%0Avar endsWith = (str, searchString, position) => {%0A str = String(str);%0A if (position === void 0 || position > str.length) {%0A position = str.length;%0A }%0A position -= searchString.length;%0A const lastIndex = str.indexOf(searchString, position);%0A return lastIndex !== -1 && lastIndex === position;%0A};%0Avar toArray = (thing) => {%0A if (!thing)%0A return null;%0A if (isArray(thing))%0A return thing;%0A let i = thing.length;%0A if (!isNumber(i))%0A return null;%0A const arr = new Array(i);%0A while (i-- > 0) {%0A arr[i] = thing[i];%0A }%0A return arr;%0A};%0Avar isTypedArray = ((TypedArray) => {%0A return (thing) => {%0A return TypedArray && thing instanceof TypedArray;%0A };%0A})(typeof Uint8Array !== "undefined" && getPrototypeOf(Uint8Array));%0Avar forEachEntry = (obj, fn) => {%0A const generator = obj && obj[Symbol.iterator];%0A const iterator = generator.call(obj);%0A let result;%0A while ((result = iterator.next()) && !result.done) {%0A const pair = result.value;%0A fn.call(obj, pair[0], pair[1]);%0A }%0A};%0Avar matchAll = (regExp, str) => {%0A let matches;%0A const arr = [];%0A while ((matches = regExp.exec(str)) !== null) {%0A arr.push(matches);%0A }%0A return arr;%0A};%0Avar isHTMLForm = kindOfTest("HTMLFormElement");%0Avar toCamelCase = (str) => {%0A return str.toLowerCase().replace(%0A /[-_\\s]([a-z\\d])(\\w*)/g,%0A function replacer(m, p1, p2) {%0A return p1.toUpperCase() + p2;%0A }%0A );%0A};%0Avar hasOwnProperty = (({ hasOwnProperty: hasOwnProperty2 }) => (obj, prop) => hasOwnProperty2.call(obj, prop))(Object.prototype);%0Avar isRegExp = kindOfTest("RegExp");%0Avar reduceDescriptors = (obj, reducer) => {%0A const descriptors2 = Object.getOwnPropertyDescriptors(obj);%0A const reducedDescriptors = {};%0A forEach(descriptors2, (descriptor, name) => {%0A if (reducer(descriptor, name, obj) !== false) {%0A reducedDescriptors[name] = descriptor;%0A }%0A });%0A Object.defineProperties(obj, reducedDescriptors);%0A};%0Avar freezeMethods = (obj) => {%0A reduceDescriptors(obj, (descriptor, name) => {%0A if (isFunction(obj) && ["arguments", "caller", "callee"].indexOf(name) !== -1) {%0A return false;%0A }%0A const value = obj[name];%0A if (!isFunction(value))%0A return;%0A descriptor.enumerable = false;%0A if ("writable" in descriptor) {%0A descriptor.writable = false;%0A return;%0A }%0A if (!descriptor.set) {%0A descriptor.set = () => {%0A throw Error("Can not rewrite read-only method \'" + name + "\'");%0A };%0A }%0A });%0A};%0Avar toObjectSet = (arrayOrString, delimiter) => {%0A const obj = {};%0A const define = (arr) => {%0A arr.forEach((value) => {%0A obj[value] = true;%0A });%0A };%0A isArray(arrayOrString) ? define(arrayOrString) : define(String(arrayOrString).split(delimiter));%0A return obj;%0A};%0Avar noop = () => {%0A};%0Avar toFiniteNumber = (value, defaultValue) => {%0A value = +value;%0A return Number.isFinite(value) ? value : defaultValue;%0A};%0Avar ALPHA = "abcdefghijklmnopqrstuvwxyz";%0Avar DIGIT = "0123456789";%0Avar ALPHABET = {%0A DIGIT,%0A ALPHA,%0A ALPHA_DIGIT: ALPHA + ALPHA.toUpperCase() + DIGIT%0A};%0Avar generateString = (size = 16, alphabet = ALPHABET.ALPHA_DIGIT) => {%0A let str = "";%0A const { length } = alphabet;%0A while (size--) {%0A str += alphabet[Math.random() * length | 0];%0A }%0A return str;%0A};%0Afunction isSpecCompliantForm(thing) {%0A return !!(thing && isFunction(thing.append) && thing[Symbol.toStringTag] === "FormData" && thing[Symbol.iterator]);%0A}%0Avar toJSONObject = (obj) => {%0A const stack = new Array(10);%0A const visit = (source, i) => {%0A if (isObject(source)) {%0A if (stack.indexOf(source) >= 0) {%0A return;%0A }%0A if (!("toJSON" in source)) {%0A stack[i] = source;%0A const target = isArray(source) ? [] : {};%0A forEach(source, (value, key) => {%0A const reducedValue = visit(value, i + 1);%0A !isUndefined(reducedValue) && (target[key] = reducedValue);%0A });%0A stack[i] = void 0;%0A return target;%0A }%0A }%0A return source;%0A };%0A return visit(obj, 0);%0A};%0Avar isAsyncFn = kindOfTest("AsyncFunction");%0Avar isThenable = (thing) => thing && (isObject(thing) || isFunction(thing)) && isFunction(thing.then) && isFunction(thing.catch);%0Avar utils_default = {%0A isArray,%0A isArrayBuffer,%0A isBuffer,%0A isFormData,%0A isArrayBufferView,%0A isString,%0A isNumber,%0A isBoolean,%0A isObject,%0A isPlainObject,%0A isUndefined,%0A isDate,%0A isFile,%0A isBlob,%0A isRegExp,%0A isFunction,%0A isStream,%0A isURLSearchParams,%0A isTypedArray,%0A isFileList,%0A forEach,%0A merge,%0A extend,%0A trim,%0A stripBOM,%0A inherits,%0A toFlatObject,%0A kindOf,%0A kindOfTest,%0A endsWith,%0A toArray,%0A forEachEntry,%0A matchAll,%0A isHTMLForm,%0A hasOwnProperty,%0A hasOwnProp: hasOwnProperty,%0A // an alias to avoid ESLint no-prototype-builtins detection%0A reduceDescriptors,%0A freezeMethods,%0A toObjectSet,%0A toCamelCase,%0A noop,%0A toFiniteNumber,%0A findKey,%0A global: _global,%0A isContextDefined,%0A ALPHABET,%0A generateString,%0A isSpecCompliantForm,%0A toJSONObject,%0A isAsyncFn,%0A isThenable%0A};%0A%0A// node_modules/axios/lib/core/AxiosError.js%0Afunction AxiosError(message, code, config, request, response) {%0A Error.call(this);%0A if (Error.captureStackTrace) {%0A Error.captureStackTrace(this, this.constructor);%0A } else {%0A this.stack = new Error().stack;%0A }%0A this.message = message;%0A this.name = "AxiosError";%0A code && (this.code = code);%0A config && (this.config = config);%0A request && (this.request = request);%0A response && (this.response = response);%0A}%0Autils_default.inherits(AxiosError, Error, {%0A toJSON: function toJSON() {%0A return {%0A // Standard%0A message: this.message,%0A name: this.name,%0A // Microsoft%0A description: this.description,%0A number: this.number,%0A // Mozilla%0A fileName: this.fileName,%0A lineNumber: this.lineNumber,%0A columnNumber: this.columnNumber,%0A stack: this.stack,%0A // Axios%0A config: utils_default.toJSONObject(this.config),%0A code: this.code,%0A status: this.response && this.response.status ? this.response.status : null%0A };%0A }%0A});%0Avar prototype = AxiosError.prototype;%0Avar descriptors = {};%0A[%0A "ERR_BAD_OPTION_VALUE",%0A "ERR_BAD_OPTION",%0A "ECONNABORTED",%0A "ETIMEDOUT",%0A "ERR_NETWORK",%0A "ERR_FR_TOO_MANY_REDIRECTS",%0A "ERR_DEPRECATED",%0A "ERR_BAD_RESPONSE",%0A "ERR_BAD_REQUEST",%0A "ERR_CANCELED",%0A "ERR_NOT_SUPPORT",%0A "ERR_INVALID_URL"%0A // eslint-disable-next-line func-names%0A].forEach((code) => {%0A descriptors[code] = { value: code };%0A});%0AObject.defineProperties(AxiosError, descriptors);%0AObject.defineProperty(prototype, "isAxiosError", { value: true });%0AAxiosError.from = (error, code, config, request, response, customProps) => {%0A const axiosError = Object.create(prototype);%0A utils_default.toFlatObject(error, axiosError, function filter2(obj) {%0A return obj !== Error.prototype;%0A }, (prop) => {%0A return prop !== "isAxiosError";%0A });%0A AxiosError.call(axiosError, error.message, code, config, request, response);%0A axiosError.cause = error;%0A axiosError.name = error.name;%0A customProps && Object.assign(axiosError, customProps);%0A return axiosError;%0A};%0Avar AxiosError_default = AxiosError;%0A%0A// node_modules/axios/lib/helpers/null.js%0Avar null_default = null;%0A%0A// node_modules/axios/lib/helpers/toFormData.js%0Afunction isVisitable(thing) {%0A return utils_default.isPlainObject(thing) || utils_default.isArray(thing);%0A}%0Afunction removeBrackets(key) {%0A return utils_default.endsWith(key, "[]") ? key.slice(0, -2) : key;%0A}%0Afunction renderKey(path, key, dots) {%0A if (!path)%0A return key;%0A return path.concat(key).map(function each(token, i) {%0A token = removeBrackets(token);%0A return !dots && i ? "[" + token + "]" : token;%0A }).join(dots ? "." : "");%0A}%0Afunction isFlatArray(arr) {%0A return utils_default.isArray(arr) && !arr.some(isVisitable);%0A}%0Avar predicates = utils_default.toFlatObject(utils_default, {}, null, function filter(prop) {%0A return /^is[A-Z]/.test(prop);%0A});%0Afunction toFormData(obj, formData, options) {%0A if (!utils_default.isObject(obj)) {%0A throw new TypeError("target must be an object");%0A }%0A formData = formData || new (null_default || FormData)();%0A options = utils_default.toFlatObject(options, {%0A metaTokens: true,%0A dots: false,%0A indexes: false%0A }, false, function defined(option, source) {%0A return !utils_default.isUndefined(source[option]);%0A });%0A const metaTokens = options.metaTokens;%0A const visitor = options.visitor || defaultVisitor;%0A const dots = options.dots;%0A const indexes = options.indexes;%0A const _Blob = options.Blob || typeof Blob !== "undefined" && Blob;%0A const useBlob = _Blob && utils_default.isSpecCompliantForm(formData);%0A if (!utils_default.isFunction(visitor)) {%0A throw new TypeError("visitor must be a function");%0A }%0A function convertValue(value) {%0A if (value === null)%0A return "";%0A if (utils_default.isDate(value)) {%0A return value.toISOString();%0A }%0A if (!useBlob && utils_default.isBlob(value)) {%0A throw new AxiosError_default("Blob is not supported. Use a Buffer instead.");%0A }%0A if (utils_default.isArrayBuffer(value) || utils_default.isTypedArray(value)) {%0A return useBlob && typeof Blob === "function" ? new Blob([value]) : Buffer.from(value);%0A }%0A return value;%0A }%0A function defaultVisitor(value, key, path) {%0A let arr = value;%0A if (value && !path && typeof value === "object") {%0A if (utils_default.endsWith(key, "{}")) {%0A key = metaTokens ? key : key.slice(0, -2);%0A value = JSON.stringify(value);%0A } else if (utils_default.isArray(value) && isFlatArray(value) || (utils_default.isFileList(value) || utils_default.endsWith(key, "[]")) && (arr = utils_default.toArray(value))) {%0A key = removeBrackets(key);%0A arr.forEach(function each(el, index) {%0A !(utils_default.isUndefined(el) || el === null) && formData.append(%0A // eslint-disable-next-line no-nested-ternary%0A indexes === true ? renderKey([key], index, dots) : indexes === null ? key : key + "[]",%0A convertValue(el)%0A );%0A });%0A return false;%0A }%0A }%0A if (isVisitable(value)) {%0A return true;%0A }%0A formData.append(renderKey(path, key, dots), convertValue(value));%0A return false;%0A }%0A const stack = [];%0A const exposedHelpers = Object.assign(predicates, {%0A defaultVisitor,%0A convertValue,%0A isVisitable%0A });%0A function build(value, path) {%0A if (utils_default.isUndefined(value))%0A return;%0A if (stack.indexOf(value) !== -1) {%0A throw Error("Circular reference detected in " + path.join("."));%0A }%0A stack.push(value);%0A utils_default.forEach(value, function each(el, key) {%0A const result = !(utils_default.isUndefined(el) || el === null) && visitor.call(%0A formData,%0A el,%0A utils_default.isString(key) ? key.trim() : key,%0A path,%0A exposedHelpers%0A );%0A if (result === true) {%0A build(el, path ? path.concat(key) : [key]);%0A }%0A });%0A stack.pop();%0A }%0A if (!utils_default.isObject(obj)) {%0A throw new TypeError("data must be an object");%0A }%0A build(obj);%0A return formData;%0A}%0Avar toFormData_default = toFormData;%0A%0A// node_modules/axios/lib/helpers/AxiosURLSearchParams.js%0Afunction encode(str) {%0A const charMap = {%0A "!": "%2521",%0A "\'": "%2527",%0A "(": "%2528",%0A ")": "%2529",%0A "~": "%257E",%0A "%2520": "+",%0A "%2500": "\\0"%0A };%0A return encodeURIComponent(str).replace(/[!\'()~]|%2520|%2500/g, function replacer(match) {%0A return charMap[match];%0A });%0A}%0Afunction AxiosURLSearchParams(params, options) {%0A this._pairs = [];%0A params && toFormData_default(params, this, options);%0A}%0Avar prototype2 = AxiosURLSearchParams.prototype;%0Aprototype2.append = function append(name, value) {%0A this._pairs.push([name, value]);%0A};%0Aprototype2.toString = function toString2(encoder2) {%0A const _encode = encoder2 ? function(value) {%0A return encoder2.call(this, value, encode);%0A } : encode;%0A return this._pairs.map(function each(pair) {%0A return _encode(pair[0]) + "=" + _encode(pair[1]);%0A }, "").join("&");%0A};%0Avar AxiosURLSearchParams_default = AxiosURLSearchParams;%0A%0A// node_modules/axios/lib/helpers/buildURL.js%0Afunction encode2(val) {%0A return encodeURIComponent(val).replace(/%253A/gi, ":").replace(/%2524/g, "$").replace(/%252C/gi, ",").replace(/%2520/g, "+").replace(/%255B/gi, "[").replace(/%255D/gi, "]");%0A}%0Afunction buildURL(url, params, options) {%0A if (!params) {%0A return url;%0A }%0A const _encode = options && options.encode || encode2;%0A const serializeFn = options && options.serialize;%0A let serializedParams;%0A if (serializeFn) {%0A serializedParams = serializeFn(params, options);%0A } else {%0A serializedParams = utils_default.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams_default(params, options).toString(_encode);%0A }%0A if (serializedParams) {%0A const hashmarkIndex = url.indexOf("%23");%0A if (hashmarkIndex !== -1) {%0A url = url.slice(0, hashmarkIndex);%0A }%0A url += (url.indexOf("?") === -1 ? "?" : "&") + serializedParams;%0A }%0A return url;%0A}%0A%0A// node_modules/axios/lib/core/InterceptorManager.js%0Avar InterceptorManager = class {%0A constructor() {%0A this.handlers = [];%0A }%0A /**%0A * Add a new interceptor to the stack%0A *%0A * @param {Function} fulfilled The function to handle `then` for a `Promise`%0A * @param {Function} rejected The function to handle `reject` for a `Promise`%0A *%0A * @return {Number} An ID used to remove interceptor later%0A */%0A use(fulfilled, rejected, options) {%0A this.handlers.push({%0A fulfilled,%0A rejected,%0A synchronous: options ? options.synchronous : false,%0A runWhen: options ? options.runWhen : null%0A });%0A return this.handlers.length - 1;%0A }%0A /**%0A * Remove an interceptor from the stack%0A *%0A * @param {Number} id The ID that was returned by `use`%0A *%0A * @returns {Boolean} `true` if the interceptor was removed, `false` otherwise%0A */%0A eject(id) {%0A if (this.handlers[id]) {%0A this.handlers[id] = null;%0A }%0A }%0A /**%0A * Clear all interceptors from the stack%0A *%0A * @returns {void}%0A */%0A clear() {%0A if (this.handlers) {%0A this.handlers = [];%0A }%0A }%0A /**%0A * Iterate over all the registered interceptors%0A *%0A * This method is particularly useful for skipping over any%0A * interceptors that may have become `null` calling `eject`.%0A *%0A * @param {Function} fn The function to call for each interceptor%0A *%0A * @returns {void}%0A */%0A forEach(fn) {%0A utils_default.forEach(this.handlers, function forEachHandler(h) {%0A if (h !== null) {%0A fn(h);%0A }%0A });%0A }%0A};%0Avar InterceptorManager_default = InterceptorManager;%0A%0A// node_modules/axios/lib/defaults/transitional.js%0Avar transitional_default = {%0A silentJSONParsing: true,%0A forcedJSONParsing: true,%0A clarifyTimeoutError: false%0A};%0A%0A// node_modules/axios/lib/platform/browser/classes/URLSearchParams.js%0Avar URLSearchParams_default = typeof URLSearchParams !== "undefined" ? URLSearchParams : AxiosURLSearchParams_default;%0A%0A// node_modules/axios/lib/platform/browser/classes/FormData.js%0Avar FormData_default = typeof FormData !== "undefined" ? FormData : null;%0A%0A// node_modules/axios/lib/platform/browser/classes/Blob.js%0Avar Blob_default = typeof Blob !== "undefined" ? Blob : null;%0A%0A// node_modules/axios/lib/platform/browser/index.js%0Avar isStandardBrowserEnv = (() => {%0A let product;%0A if (typeof navigator !== "undefined" && ((product = navigator.product) === "ReactNative" || product === "NativeScript" || product === "NS")) {%0A return false;%0A }%0A return typeof window !== "undefined" && typeof document !== "undefined";%0A})();%0Avar isStandardBrowserWebWorkerEnv = (() => {%0A return typeof WorkerGlobalScope !== "undefined" && // eslint-disable-next-line no-undef%0A self instanceof WorkerGlobalScope && typeof self.importScripts === "function";%0A})();%0Avar browser_default = {%0A isBrowser: true,%0A classes: {%0A URLSearchParams: URLSearchParams_default,%0A FormData: FormData_default,%0A Blob: Blob_default%0A },%0A isStandardBrowserEnv,%0A isStandardBrowserWebWorkerEnv,%0A protocols: ["http", "https", "file", "blob", "url", "data"]%0A};%0A%0A// node_modules/axios/lib/helpers/toURLEncodedForm.js%0Afunction toURLEncodedForm(data, options) {%0A return toFormData_default(data, new browser_default.classes.URLSearchParams(), Object.assign({%0A visitor: function(value, key, path, helpers) {%0A if (browser_default.isNode && utils_default.isBuffer(value)) {%0A this.append(key, value.toString("base64"));%0A return false;%0A }%0A return helpers.defaultVisitor.apply(this, arguments);%0A }%0A }, options));%0A}%0A%0A// node_modules/axios/lib/helpers/formDataToJSON.js%0Afunction parsePropPath(name) {%0A return utils_default.matchAll(/\\w+|\\[(\\w*)]/g, name).map((match) => {%0A return match[0] === "[]" ? "" : match[1] || match[0];%0A });%0A}%0Afunction arrayToObject(arr) {%0A const obj = {};%0A const keys = Object.keys(arr);%0A let i;%0A const len = keys.length;%0A let key;%0A for (i = 0; i < len; i++) {%0A key = keys[i];%0A obj[key] = arr[key];%0A }%0A return obj;%0A}%0Afunction formDataToJSON(formData) {%0A function buildPath(path, value, target, index) {%0A let name = path[index++];%0A const isNumericKey = Number.isFinite(+name);%0A const isLast = index >= path.length;%0A name = !name && utils_default.isArray(target) ? target.length : name;%0A if (isLast) {%0A if (utils_default.hasOwnProp(target, name)) {%0A target[name] = [target[name], value];%0A } else {%0A target[name] = value;%0A }%0A return !isNumericKey;%0A }%0A if (!target[name] || !utils_default.isObject(target[name])) {%0A target[name] = [];%0A }%0A const result = buildPath(path, value, target[name], index);%0A if (result && utils_default.isArray(target[name])) {%0A target[name] = arrayToObject(target[name]);%0A }%0A return !isNumericKey;%0A }%0A if (utils_default.isFormData(formData) && utils_default.isFunction(formData.entries)) {%0A const obj = {};%0A utils_default.forEachEntry(formData, (name, value) => {%0A buildPath(parsePropPath(name), value, obj, 0);%0A });%0A return obj;%0A }%0A return null;%0A}%0Avar formDataToJSON_default = formDataToJSON;%0A%0A// node_modules/axios/lib/defaults/index.js%0Avar DEFAULT_CONTENT_TYPE = {%0A "Content-Type": void 0%0A};%0Afunction stringifySafely(rawValue, parser, encoder2) {%0A if (utils_default.isString(rawValue)) {%0A try {%0A (parser || JSON.parse)(rawValue);%0A return utils_default.trim(rawValue);%0A } catch (e) {%0A if (e.name !== "SyntaxError") {%0A throw e;%0A }%0A }%0A }%0A return (encoder2 || JSON.stringify)(rawValue);%0A}%0Avar defaults = {%0A transitional: transitional_default,%0A adapter: ["xhr", "http"],%0A transformRequest: [function transformRequest(data, headers) {%0A const contentType = headers.getContentType() || "";%0A const hasJSONContentType = contentType.indexOf("application/json") > -1;%0A const isObjectPayload = utils_default.isObject(data);%0A if (isObjectPayload && utils_default.isHTMLForm(data)) {%0A data = new FormData(data);%0A }%0A const isFormData2 = utils_default.isFormData(data);%0A if (isFormData2) {%0A if (!hasJSONContentType) {%0A return data;%0A }%0A return hasJSONContentType ? JSON.stringify(formDataToJSON_default(data)) : data;%0A }%0A if (utils_default.isArrayBuffer(data) || utils_default.isBuffer(data) || utils_default.isStream(data) || utils_default.isFile(data) || utils_default.isBlob(data)) {%0A return data;%0A }%0A if (utils_default.isArrayBufferView(data)) {%0A return data.buffer;%0A }%0A if (utils_default.isURLSearchParams(data)) {%0A headers.setContentType("application/x-www-form-urlencoded;charset=utf-8", false);%0A return data.toString();%0A }%0A let isFileList2;%0A if (isObjectPayload) {%0A if (contentType.indexOf("application/x-www-form-urlencoded") > -1) {%0A return toURLEncodedForm(data, this.formSerializer).toString();%0A }%0A if ((isFileList2 = utils_default.isFileList(data)) || contentType.indexOf("multipart/form-data") > -1) {%0A const _FormData = this.env && this.env.FormData;%0A return toFormData_default(%0A isFileList2 ? { "files[]": data } : data,%0A _FormData && new _FormData(),%0A this.formSerializer%0A );%0A }%0A }%0A if (isObjectPayload || hasJSONContentType) {%0A headers.setContentType("application/json", false);%0A return stringifySafely(data);%0A }%0A return data;%0A }],%0A transformResponse: [function transformResponse(data) {%0A const transitional2 = this.transitional || defaults.transitional;%0A const forcedJSONParsing = transitional2 && transitional2.forcedJSONParsing;%0A const JSONRequested = this.responseType === "json";%0A if (data && utils_default.isString(data) && (forcedJSONParsing && !this.responseType || JSONRequested)) {%0A const silentJSONParsing = transitional2 && transitional2.silentJSONParsing;%0A const strictJSONParsing = !silentJSONParsing && JSONRequested;%0A try {%0A return JSON.parse(data);%0A } catch (e) {%0A if (strictJSONParsing) {%0A if (e.name === "SyntaxError") {%0A throw AxiosError_default.from(e, AxiosError_default.ERR_BAD_RESPONSE, this, null, this.response);%0A }%0A throw e;%0A }%0A }%0A }%0A return data;%0A }],%0A /**%0A * A timeout in milliseconds to abort a request. If set to 0 (default) a%0A * timeout is not created.%0A */%0A timeout: 0,%0A xsrfCookieName: "XSRF-TOKEN",%0A xsrfHeaderName: "X-XSRF-TOKEN",%0A maxContentLength: -1,%0A maxBodyLength: -1,%0A env: {%0A FormData: browser_default.classes.FormData,%0A Blob: browser_default.classes.Blob%0A },%0A validateStatus: function validateStatus(status) {%0A return status >= 200 && status < 300;%0A },%0A headers: {%0A common: {%0A "Accept": "application/json, text/plain, */*"%0A }%0A }%0A};%0Autils_default.forEach(["delete", "get", "head"], function forEachMethodNoData(method) {%0A defaults.headers[method] = {};%0A});%0Autils_default.forEach(["post", "put", "patch"], function forEachMethodWithData(method) {%0A defaults.headers[method] = utils_default.merge(DEFAULT_CONTENT_TYPE);%0A});%0Avar defaults_default = defaults;%0A%0A// node_modules/axios/lib/helpers/parseHeaders.js%0Avar ignoreDuplicateOf = utils_default.toObjectSet([%0A "age",%0A "authorization",%0A "content-length",%0A "content-type",%0A "etag",%0A "expires",%0A "from",%0A "host",%0A "if-modified-since",%0A "if-unmodified-since",%0A "last-modified",%0A "location",%0A "max-forwards",%0A "proxy-authorization",%0A "referer",%0A "retry-after",%0A "user-agent"%0A]);%0Avar parseHeaders_default = (rawHeaders) => {%0A const parsed = {};%0A let key;%0A let val;%0A let i;%0A rawHeaders && rawHeaders.split("\\n").forEach(function parser(line) {%0A i = line.indexOf(":");%0A key = line.substring(0, i).trim().toLowerCase();%0A val = line.substring(i + 1).trim();%0A if (!key || parsed[key] && ignoreDuplicateOf[key]) {%0A return;%0A }%0A if (key === "set-cookie") {%0A if (parsed[key]) {%0A parsed[key].push(val);%0A } else {%0A parsed[key] = [val];%0A }%0A } else {%0A parsed[key] = parsed[key] ? parsed[key] + ", " + val : val;%0A }%0A });%0A return parsed;%0A};%0A%0A// node_modules/axios/lib/core/AxiosHeaders.js%0Avar $internals = Symbol("internals");%0Afunction normalizeHeader(header) {%0A return header && String(header).trim().toLowerCase();%0A}%0Afunction normalizeValue(value) {%0A if (value === false || value == null) {%0A return value;%0A }%0A return utils_default.isArray(value) ? value.map(normalizeValue) : String(value);%0A}%0Afunction parseTokens(str) {%0A const tokens = /* @__PURE__ */ Object.create(null);%0A const tokensRE = /([^\\s,;=]+)\\s*(?:=\\s*([^,;]+))?/g;%0A let match;%0A while (match = tokensRE.exec(str)) {%0A tokens[match[1]] = match[2];%0A }%0A return tokens;%0A}%0Avar isValidHeaderName = (str) => /^[-_a-zA-Z0-9^`|~,!%23$%&\'*+.]+$/.test(str.trim());%0Afunction matchHeaderValue(context, value, header, filter2, isHeaderNameFilter) {%0A if (utils_default.isFunction(filter2)) {%0A return filter2.call(this, value, header);%0A }%0A if (isHeaderNameFilter) {%0A value = header;%0A }%0A if (!utils_default.isString(value))%0A return;%0A if (utils_default.isString(filter2)) {%0A return value.indexOf(filter2) !== -1;%0A }%0A if (utils_default.isRegExp(filter2)) {%0A return filter2.test(value);%0A }%0A}%0Afunction formatHeader(header) {%0A return header.trim().toLowerCase().replace(/([a-z\\d])(\\w*)/g, (w, char, str) => {%0A return char.toUpperCase() + str;%0A });%0A}%0Afunction buildAccessors(obj, header) {%0A const accessorName = utils_default.toCamelCase(" " + header);%0A ["get", "set", "has"].forEach((methodName) => {%0A Object.defineProperty(obj, methodName + accessorName, {%0A value: function(arg1, arg2, arg3) {%0A return this[methodName].call(this, header, arg1, arg2, arg3);%0A },%0A configurable: true%0A });%0A });%0A}%0Avar AxiosHeaders = class {%0A constructor(headers) {%0A headers && this.set(headers);%0A }%0A set(header, valueOrRewrite, rewrite) {%0A const self2 = this;%0A function setHeader(_value, _header, _rewrite) {%0A const lHeader = normalizeHeader(_header);%0A if (!lHeader) {%0A throw new Error("header name must be a non-empty string");%0A }%0A const key = utils_default.findKey(self2, lHeader);%0A if (!key || self2[key] === void 0 || _rewrite === true || _rewrite === void 0 && self2[key] !== false) {%0A self2[key || _header] = normalizeValue(_value);%0A }%0A }%0A const setHeaders = (headers, _rewrite) => utils_default.forEach(headers, (_value, _header) => setHeader(_value, _header, _rewrite));%0A if (utils_default.isPlainObject(header) || header instanceof this.constructor) {%0A setHeaders(header, valueOrRewrite);%0A } else if (utils_default.isString(header) && (header = header.trim()) && !isValidHeaderName(header)) {%0A setHeaders(parseHeaders_default(header), valueOrRewrite);%0A } else {%0A header != null && setHeader(valueOrRewrite, header, rewrite);%0A }%0A return this;%0A }%0A get(header, parser) {%0A header = normalizeHeader(header);%0A if (header) {%0A const key = utils_default.findKey(this, header);%0A if (key) {%0A const value = this[key];%0A if (!parser) {%0A return value;%0A }%0A if (parser === true) {%0A return parseTokens(value);%0A }%0A if (utils_default.isFunction(parser)) {%0A return parser.call(this, value, key);%0A }%0A if (utils_default.isRegExp(parser)) {%0A return parser.exec(value);%0A }%0A throw new TypeError("parser must be boolean|regexp|function");%0A }%0A }%0A }%0A has(header, matcher) {%0A header = normalizeHeader(header);%0A if (header) {%0A const key = utils_default.findKey(this, header);%0A return !!(key && this[key] !== void 0 && (!matcher || matchHeaderValue(this, this[key], key, matcher)));%0A }%0A return false;%0A }%0A delete(header, matcher) {%0A const self2 = this;%0A let deleted = false;%0A function deleteHeader(_header) {%0A _header = normalizeHeader(_header);%0A if (_header) {%0A const key = utils_default.findKey(self2, _header);%0A if (key && (!matcher || matchHeaderValue(self2, self2[key], key, matcher))) {%0A delete self2[key];%0A deleted = true;%0A }%0A }%0A }%0A if (utils_default.isArray(header)) {%0A header.forEach(deleteHeader);%0A } else {%0A deleteHeader(header);%0A }%0A return deleted;%0A }%0A clear(matcher) {%0A const keys = Object.keys(this);%0A let i = keys.length;%0A let deleted = false;%0A while (i--) {%0A const key = keys[i];%0A if (!matcher || matchHeaderValue(this, this[key], key, matcher, true)) {%0A delete this[key];%0A deleted = true;%0A }%0A }%0A return deleted;%0A }%0A normalize(format) {%0A const self2 = this;%0A const headers = {};%0A utils_default.forEach(this, (value, header) => {%0A const key = utils_default.findKey(headers, header);%0A if (key) {%0A self2[key] = normalizeValue(value);%0A delete self2[header];%0A return;%0A }%0A const normalized = format ? formatHeader(header) : String(header).trim();%0A if (normalized !== header) {%0A delete self2[header];%0A }%0A self2[normalized] = normalizeValue(value);%0A headers[normalized] = true;%0A });%0A return this;%0A }%0A concat(...targets) {%0A return this.constructor.concat(this, ...targets);%0A }%0A toJSON(asStrings) {%0A const obj = /* @__PURE__ */ Object.create(null);%0A utils_default.forEach(this, (value, header) => {%0A value != null && value !== false && (obj[header] = asStrings && utils_default.isArray(value) ? value.join(", ") : value);%0A });%0A return obj;%0A }%0A [Symbol.iterator]() {%0A return Object.entries(this.toJSON())[Symbol.iterator]();%0A }%0A toString() {%0A return Object.entries(this.toJSON()).map(([header, value]) => header + ": " + value).join("\\n");%0A }%0A get [Symbol.toStringTag]() {%0A return "AxiosHeaders";%0A }%0A static from(thing) {%0A return thing instanceof this ? thing : new this(thing);%0A }%0A static concat(first, ...targets) {%0A const computed = new this(first);%0A targets.forEach((target) => computed.set(target));%0A return computed;%0A }%0A static accessor(header) {%0A const internals = this[$internals] = this[$internals] = {%0A accessors: {}%0A };%0A const accessors = internals.accessors;%0A const prototype3 = this.prototype;%0A function defineAccessor(_header) {%0A const lHeader = normalizeHeader(_header);%0A if (!accessors[lHeader]) {%0A buildAccessors(prototype3, _header);%0A accessors[lHeader] = true;%0A }%0A }%0A utils_default.isArray(header) ? header.forEach(defineAccessor) : defineAccessor(header);%0A return this;%0A }%0A};%0AAxiosHeaders.accessor(["Content-Type", "Content-Length", "Accept", "Accept-Encoding", "User-Agent", "Authorization"]);%0Autils_default.freezeMethods(AxiosHeaders.prototype);%0Autils_default.freezeMethods(AxiosHeaders);%0Avar AxiosHeaders_default = AxiosHeaders;%0A%0A// node_modules/axios/lib/core/transformData.js%0Afunction transformData(fns, response) {%0A const config = this || defaults_default;%0A const context = response || config;%0A const headers = AxiosHeaders_default.from(context.headers);%0A let data = context.data;%0A utils_default.forEach(fns, function transform(fn) {%0A data = fn.call(config, data, headers.normalize(), response ? response.status : void 0);%0A });%0A headers.normalize();%0A return data;%0A}%0A%0A// node_modules/axios/lib/cancel/isCancel.js%0Afunction isCancel(value) {%0A return !!(value && value.__CANCEL__);%0A}%0A%0A// node_modules/axios/lib/cancel/CanceledError.js%0Afunction CanceledError(message, config, request) {%0A AxiosError_default.call(this, message == null ? "canceled" : message, AxiosError_default.ERR_CANCELED, config, request);%0A this.name = "CanceledError";%0A}%0Autils_default.inherits(CanceledError, AxiosError_default, {%0A __CANCEL__: true%0A});%0Avar CanceledError_default = CanceledError;%0A%0A// node_modules/axios/lib/core/settle.js%0Afunction settle(resolve, reject, response) {%0A const validateStatus2 = response.config.validateStatus;%0A if (!response.status || !validateStatus2 || validateStatus2(response.status)) {%0A resolve(response);%0A } else {%0A reject(new AxiosError_default(%0A "Request failed with status code " + response.status,%0A [AxiosError_default.ERR_BAD_REQUEST, AxiosError_default.ERR_BAD_RESPONSE][Math.floor(response.status / 100) - 4],%0A response.config,%0A response.request,%0A response%0A ));%0A }%0A}%0A%0A// node_modules/axios/lib/helpers/cookies.js%0Avar cookies_default = browser_default.isStandardBrowserEnv ? (%0A // Standard browser envs support document.cookie%0A function standardBrowserEnv() {%0A return {%0A write: function write(name, value, expires, path, domain, secure) {%0A const cookie = [];%0A cookie.push(name + "=" + encodeURIComponent(value));%0A if (utils_default.isNumber(expires)) {%0A cookie.push("expires=" + new Date(expires).toGMTString());%0A }%0A if (utils_default.isString(path)) {%0A cookie.push("path=" + path);%0A }%0A if (utils_default.isString(domain)) {%0A cookie.push("domain=" + domain);%0A }%0A if (secure === true) {%0A cookie.push("secure");%0A }%0A document.cookie = cookie.join("; ");%0A },%0A read: function read(name) {%0A const match = document.cookie.match(new RegExp("(^|;\\\\s*)(" + name + ")=([^;]*)"));%0A return match ? decodeURIComponent(match[3]) : null;%0A },%0A remove: function remove(name) {%0A this.write(name, "", Date.now() - 864e5);%0A }%0A };%0A }()%0A) : (%0A // Non standard browser env (web workers, react-native) lack needed support.%0A function nonStandardBrowserEnv() {%0A return {%0A write: function write() {%0A },%0A read: function read() {%0A return null;%0A },%0A remove: function remove() {%0A }%0A };%0A }()%0A);%0A%0A// node_modules/axios/lib/helpers/isAbsoluteURL.js%0Afunction isAbsoluteURL(url) {%0A return /^([a-z][a-z\\d+\\-.]*:)?\\/\\//i.test(url);%0A}%0A%0A// node_modules/axios/lib/helpers/combineURLs.js%0Afunction combineURLs(baseURL, relativeURL) {%0A return relativeURL ? baseURL.replace(/\\/+$/, "") + "/" + relativeURL.replace(/^\\/+/, "") : baseURL;%0A}%0A%0A// node_modules/axios/lib/core/buildFullPath.js%0Afunction buildFullPath(baseURL, requestedURL) {%0A if (baseURL && !isAbsoluteURL(requestedURL)) {%0A return combineURLs(baseURL, requestedURL);%0A }%0A return requestedURL;%0A}%0A%0A// node_modules/axios/lib/helpers/isURLSameOrigin.js%0Avar isURLSameOrigin_default = browser_default.isStandardBrowserEnv ? (%0A // Standard browser envs have full support of the APIs needed to test%0A // whether the request URL is of the same origin as current location.%0A function standardBrowserEnv2() {%0A const msie = /(msie|trident)/i.test(navigator.userAgent);%0A const urlParsingNode = document.createElement("a");%0A let originURL;%0A function resolveURL(url) {%0A let href = url;%0A if (msie) {%0A urlParsingNode.setAttribute("href", href);%0A href = urlParsingNode.href;%0A }%0A urlParsingNode.setAttribute("href", href);%0A return {%0A href: urlParsingNode.href,%0A protocol: urlParsingNode.protocol ? urlParsingNode.protocol.replace(/:$/, "") : "",%0A host: urlParsingNode.host,%0A search: urlParsingNode.search ? urlParsingNode.search.replace(/^\\?/, "") : "",%0A hash: urlParsingNode.hash ? urlParsingNode.hash.replace(/^%23/, "") : "",%0A hostname: urlParsingNode.hostname,%0A port: urlParsingNode.port,%0A pathname: urlParsingNode.pathname.charAt(0) === "/" ? urlParsingNode.pathname : "/" + urlParsingNode.pathname%0A };%0A }%0A originURL = resolveURL(window.location.href);%0A return function isURLSameOrigin(requestURL) {%0A const parsed = utils_default.isString(requestURL) ? resolveURL(requestURL) : requestURL;%0A return parsed.protocol === originURL.protocol && parsed.host === originURL.host;%0A };%0A }()%0A) : (%0A // Non standard browser envs (web workers, react-native) lack needed support.%0A function nonStandardBrowserEnv2() {%0A return function isURLSameOrigin() {%0A return true;%0A };%0A }()%0A);%0A%0A// node_modules/axios/lib/helpers/parseProtocol.js%0Afunction parseProtocol(url) {%0A const match = /^([-+\\w]{1,25})(:?\\/\\/|:)/.exec(url);%0A return match && match[1] || "";%0A}%0A%0A// node_modules/axios/lib/helpers/speedometer.js%0Afunction speedometer(samplesCount, min) {%0A samplesCount = samplesCount || 10;%0A const bytes = new Array(samplesCount);%0A const timestamps = new Array(samplesCount);%0A let head = 0;%0A let tail = 0;%0A let firstSampleTS;%0A min = min !== void 0 ? min : 1e3;%0A return function push(chunkLength) {%0A const now = Date.now();%0A const startedAt = timestamps[tail];%0A if (!firstSampleTS) {%0A firstSampleTS = now;%0A }%0A bytes[head] = chunkLength;%0A timestamps[head] = now;%0A let i = tail;%0A let bytesCount = 0;%0A while (i !== head) {%0A bytesCount += bytes[i++];%0A i = i % samplesCount;%0A }%0A head = (head + 1) % samplesCount;%0A if (head === tail) {%0A tail = (tail + 1) % samplesCount;%0A }%0A if (now - firstSampleTS < min) {%0A return;%0A }%0A const passed = startedAt && now - startedAt;%0A return passed ? Math.round(bytesCount * 1e3 / passed) : void 0;%0A };%0A}%0Avar speedometer_default = speedometer;%0A%0A// node_modules/axios/lib/adapters/xhr.js%0Afunction progressEventReducer(listener, isDownloadStream) {%0A let bytesNotified = 0;%0A const _speedometer = speedometer_default(50, 250);%0A return (e) => {%0A const loaded = e.loaded;%0A const total = e.lengthComputable ? e.total : void 0;%0A const progressBytes = loaded - bytesNotified;%0A const rate = _speedometer(progressBytes);%0A const inRange = loaded <= total;%0A bytesNotified = loaded;%0A const data = {%0A loaded,%0A total,%0A progress: total ? loaded / total : void 0,%0A bytes: progressBytes,%0A rate: rate ? rate : void 0,%0A estimated: rate && total && inRange ? (total - loaded) / rate : void 0,%0A event: e%0A };%0A data[isDownloadStream ? "download" : "upload"] = true;%0A listener(data);%0A };%0A}%0Avar isXHRAdapterSupported = typeof XMLHttpRequest !== "undefined";%0Avar xhr_default = isXHRAdapterSupported && function(config) {%0A return new Promise(function dispatchXhrRequest(resolve, reject) {%0A let requestData = config.data;%0A const requestHeaders = AxiosHeaders_default.from(config.headers).normalize();%0A const responseType = config.responseType;%0A let onCanceled;%0A function done() {%0A if (config.cancelToken) {%0A config.cancelToken.unsubscribe(onCanceled);%0A }%0A if (config.signal) {%0A config.signal.removeEventListener("abort", onCanceled);%0A }%0A }%0A if (utils_default.isFormData(requestData)) {%0A if (browser_default.isStandardBrowserEnv || browser_default.isStandardBrowserWebWorkerEnv) {%0A requestHeaders.setContentType(false);%0A } else {%0A requestHeaders.setContentType("multipart/form-data;", false);%0A }%0A }%0A let request = new XMLHttpRequest();%0A if (config.auth) {%0A const username = config.auth.username || "";%0A const password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : "";%0A requestHeaders.set("Authorization", "Basic " + btoa(username + ":" + password));%0A }%0A const fullPath = buildFullPath(config.baseURL, config.url);%0A request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);%0A request.timeout = config.timeout;%0A function onloadend() {%0A if (!request) {%0A return;%0A }%0A const responseHeaders = AxiosHeaders_default.from(%0A "getAllResponseHeaders" in request && request.getAllResponseHeaders()%0A );%0A const responseData = !responseType || responseType === "text" || responseType === "json" ? request.responseText : request.response;%0A const response = {%0A data: responseData,%0A status: request.status,%0A statusText: request.statusText,%0A headers: responseHeaders,%0A config,%0A request%0A };%0A settle(function _resolve(value) {%0A resolve(value);%0A done();%0A }, function _reject(err) {%0A reject(err);%0A done();%0A }, response);%0A request = null;%0A }%0A if ("onloadend" in request) {%0A request.onloadend = onloadend;%0A } else {%0A request.onreadystatechange = function handleLoad() {%0A if (!request || request.readyState !== 4) {%0A return;%0A }%0A if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf("file:") === 0)) {%0A return;%0A }%0A setTimeout(onloadend);%0A };%0A }%0A request.onabort = function handleAbort() {%0A if (!request) {%0A return;%0A }%0A reject(new AxiosError_default("Request aborted", AxiosError_default.ECONNABORTED, config, request));%0A request = null;%0A };%0A request.onerror = function handleError() {%0A reject(new AxiosError_default("Network Error", AxiosError_default.ERR_NETWORK, config, request));%0A request = null;%0A };%0A request.ontimeout = function handleTimeout() {%0A let timeoutErrorMessage = config.timeout ? "timeout of " + config.timeout + "ms exceeded" : "timeout exceeded";%0A const transitional2 = config.transitional || transitional_default;%0A if (config.timeoutErrorMessage) {%0A timeoutErrorMessage = config.timeoutErrorMessage;%0A }%0A reject(new AxiosError_default(%0A timeoutErrorMessage,%0A transitional2.clarifyTimeoutError ? AxiosError_default.ETIMEDOUT : AxiosError_default.ECONNABORTED,%0A config,%0A request%0A ));%0A request = null;%0A };%0A if (browser_default.isStandardBrowserEnv) {%0A const xsrfValue = (config.withCredentials || isURLSameOrigin_default(fullPath)) && config.xsrfCookieName && cookies_default.read(config.xsrfCookieName);%0A if (xsrfValue) {%0A requestHeaders.set(config.xsrfHeaderName, xsrfValue);%0A }%0A }%0A requestData === void 0 && requestHeaders.setContentType(null);%0A if ("setRequestHeader" in request) {%0A utils_default.forEach(requestHeaders.toJSON(), function setRequestHeader(val, key) {%0A request.setRequestHeader(key, val);%0A });%0A }%0A if (!utils_default.isUndefined(config.withCredentials)) {%0A request.withCredentials = !!config.withCredentials;%0A }%0A if (responseType && responseType !== "json") {%0A request.responseType = config.responseType;%0A }%0A if (typeof config.onDownloadProgress === "function") {%0A request.addEventListener("progress", progressEventReducer(config.onDownloadProgress, true));%0A }%0A if (typeof config.onUploadProgress === "function" && request.upload) {%0A request.upload.addEventListener("progress", progressEventReducer(config.onUploadProgress));%0A }%0A if (config.cancelToken || config.signal) {%0A onCanceled = (cancel) => {%0A if (!request) {%0A return;%0A }%0A reject(!cancel || cancel.type ? new CanceledError_default(null, config, request) : cancel);%0A request.abort();%0A request = null;%0A };%0A config.cancelToken && config.cancelToken.subscribe(onCanceled);%0A if (config.signal) {%0A config.signal.aborted ? onCanceled() : config.signal.addEventListener("abort", onCanceled);%0A }%0A }%0A const protocol = parseProtocol(fullPath);%0A if (protocol && browser_default.protocols.indexOf(protocol) === -1) {%0A reject(new AxiosError_default("Unsupported protocol " + protocol + ":", AxiosError_default.ERR_BAD_REQUEST, config));%0A return;%0A }%0A request.send(requestData || null);%0A });%0A};%0A%0A// node_modules/axios/lib/adapters/adapters.js%0Avar knownAdapters = {%0A http: null_default,%0A xhr: xhr_default%0A};%0Autils_default.forEach(knownAdapters, (fn, value) => {%0A if (fn) {%0A try {%0A Object.defineProperty(fn, "name", { value });%0A } catch (e) {%0A }%0A Object.defineProperty(fn, "adapterName", { value });%0A }%0A});%0Avar adapters_default = {%0A getAdapter: (adapters) => {%0A adapters = utils_default.isArray(adapters) ? adapters : [adapters];%0A const { length } = adapters;%0A let nameOrAdapter;%0A let adapter;%0A for (let i = 0; i < length; i++) {%0A nameOrAdapter = adapters[i];%0A if (adapter = utils_default.isString(nameOrAdapter) ? knownAdapters[nameOrAdapter.toLowerCase()] : nameOrAdapter) {%0A break;%0A }%0A }%0A if (!adapter) {%0A if (adapter === false) {%0A throw new AxiosError_default(%0A `Adapter ${nameOrAdapter} is not supported by the environment`,%0A "ERR_NOT_SUPPORT"%0A );%0A }%0A throw new Error(%0A utils_default.hasOwnProp(knownAdapters, nameOrAdapter) ? `Adapter \'${nameOrAdapter}\' is not available in the build` : `Unknown adapter \'${nameOrAdapter}\'`%0A );%0A }%0A if (!utils_default.isFunction(adapter)) {%0A throw new TypeError("adapter is not a function");%0A }%0A return adapter;%0A },%0A adapters: knownAdapters%0A};%0A%0A// node_modules/axios/lib/core/dispatchRequest.js%0Afunction throwIfCancellationRequested(config) {%0A if (config.cancelToken) {%0A config.cancelToken.throwIfRequested();%0A }%0A if (config.signal && config.signal.aborted) {%0A throw new CanceledError_default(null, config);%0A }%0A}%0Afunction dispatchRequest(config) {%0A throwIfCancellationRequested(config);%0A config.headers = AxiosHeaders_default.from(config.headers);%0A config.data = transformData.call(%0A config,%0A config.transformRequest%0A );%0A if (["post", "put", "patch"].indexOf(config.method) !== -1) {%0A config.headers.setContentType("application/x-www-form-urlencoded", false);%0A }%0A const adapter = adapters_default.getAdapter(config.adapter || defaults_default.adapter);%0A return adapter(config).then(function onAdapterResolution(response) {%0A throwIfCancellationRequested(config);%0A response.data = transformData.call(%0A config,%0A config.transformResponse,%0A response%0A );%0A response.headers = AxiosHeaders_default.from(response.headers);%0A return response;%0A }, function onAdapterRejection(reason) {%0A if (!isCancel(reason)) {%0A throwIfCancellationRequested(config);%0A if (reason && reason.response) {%0A reason.response.data = transformData.call(%0A config,%0A config.transformResponse,%0A reason.response%0A );%0A reason.response.headers = AxiosHeaders_default.from(reason.response.headers);%0A }%0A }%0A return Promise.reject(reason);%0A });%0A}%0A%0A// node_modules/axios/lib/core/mergeConfig.js%0Avar headersToObject = (thing) => thing instanceof AxiosHeaders_default ? thing.toJSON() : thing;%0Afunction mergeConfig(config1, config2) {%0A config2 = config2 || {};%0A const config = {};%0A function getMergedValue(target, source, caseless) {%0A if (utils_default.isPlainObject(target) && utils_default.isPlainObject(source)) {%0A return utils_default.merge.call({ caseless }, target, source);%0A } else if (utils_default.isPlainObject(source)) {%0A return utils_default.merge({}, source);%0A } else if (utils_default.isArray(source)) {%0A return source.slice();%0A }%0A return source;%0A }%0A function mergeDeepProperties(a, b, caseless) {%0A if (!utils_default.isUndefined(b)) {%0A return getMergedValue(a, b, caseless);%0A } else if (!utils_default.isUndefined(a)) {%0A return getMergedValue(void 0, a, caseless);%0A }%0A }%0A function valueFromConfig2(a, b) {%0A if (!utils_default.isUndefined(b)) {%0A return getMergedValue(void 0, b);%0A }%0A }%0A function defaultToConfig2(a, b) {%0A if (!utils_default.isUndefined(b)) {%0A return getMergedValue(void 0, b);%0A } else if (!utils_default.isUndefined(a)) {%0A return getMergedValue(void 0, a);%0A }%0A }%0A function mergeDirectKeys(a, b, prop) {%0A if (prop in config2) {%0A return getMergedValue(a, b);%0A } else if (prop in config1) {%0A return getMergedValue(void 0, a);%0A }%0A }%0A const mergeMap = {%0A url: valueFromConfig2,%0A method: valueFromConfig2,%0A data: valueFromConfig2,%0A baseURL: defaultToConfig2,%0A transformRequest: defaultToConfig2,%0A transformResponse: defaultToConfig2,%0A paramsSerializer: defaultToConfig2,%0A timeout: defaultToConfig2,%0A timeoutMessage: defaultToConfig2,%0A withCredentials: defaultToConfig2,%0A adapter: defaultToConfig2,%0A responseType: defaultToConfig2,%0A xsrfCookieName: defaultToConfig2,%0A xsrfHeaderName: defaultToConfig2,%0A onUploadProgress: defaultToConfig2,%0A onDownloadProgress: defaultToConfig2,%0A decompress: defaultToConfig2,%0A maxContentLength: defaultToConfig2,%0A maxBodyLength: defaultToConfig2,%0A beforeRedirect: defaultToConfig2,%0A transport: defaultToConfig2,%0A httpAgent: defaultToConfig2,%0A httpsAgent: defaultToConfig2,%0A cancelToken: defaultToConfig2,%0A socketPath: defaultToConfig2,%0A responseEncoding: defaultToConfig2,%0A validateStatus: mergeDirectKeys,%0A headers: (a, b) => mergeDeepProperties(headersToObject(a), headersToObject(b), true)%0A };%0A utils_default.forEach(Object.keys(Object.assign({}, config1, config2)), function computeConfigValue(prop) {%0A const merge2 = mergeMap[prop] || mergeDeepProperties;%0A const configValue = merge2(config1[prop], config2[prop], prop);%0A utils_default.isUndefined(configValue) && merge2 !== mergeDirectKeys || (config[prop] = configValue);%0A });%0A return config;%0A}%0A%0A// node_modules/axios/lib/env/data.js%0Avar VERSION = "1.4.0";%0A%0A// node_modules/axios/lib/helpers/validator.js%0Avar validators = {};%0A["object", "boolean", "number", "function", "string", "symbol"].forEach((type, i) => {%0A validators[type] = function validator(thing) {%0A return typeof thing === type || "a" + (i < 1 ? "n " : " ") + type;%0A };%0A});%0Avar deprecatedWarnings = {};%0Avalidators.transitional = function transitional(validator, version, message) {%0A function formatMessage(opt, desc) {%0A return "[Axios v" + VERSION + "] Transitional option \'" + opt + "\'" + desc + (message ? ". " + message : "");%0A }%0A return (value, opt, opts) => {%0A if (validator === false) {%0A throw new AxiosError_default(%0A formatMessage(opt, " has been removed" + (version ? " in " + version : "")),%0A AxiosError_default.ERR_DEPRECATED%0A );%0A }%0A if (version && !deprecatedWarnings[opt]) {%0A deprecatedWarnings[opt] = true;%0A console.warn(%0A formatMessage(%0A opt,%0A " has been deprecated since v" + version + " and will be removed in the near future"%0A )%0A );%0A }%0A return validator ? validator(value, opt, opts) : true;%0A };%0A};%0Afunction assertOptions(options, schema, allowUnknown) {%0A if (typeof options !== "object") {%0A throw new AxiosError_default("options must be an object", AxiosError_default.ERR_BAD_OPTION_VALUE);%0A }%0A const keys = Object.keys(options);%0A let i = keys.length;%0A while (i-- > 0) {%0A const opt = keys[i];%0A const validator = schema[opt];%0A if (validator) {%0A const value = options[opt];%0A const result = value === void 0 || validator(value, opt, options);%0A if (result !== true) {%0A throw new AxiosError_default("option " + opt + " must be " + result, AxiosError_default.ERR_BAD_OPTION_VALUE);%0A }%0A continue;%0A }%0A if (allowUnknown !== true) {%0A throw new AxiosError_default("Unknown option " + opt, AxiosError_default.ERR_BAD_OPTION);%0A }%0A }%0A}%0Avar validator_default = {%0A assertOptions,%0A validators%0A};%0A%0A// node_modules/axios/lib/core/Axios.js%0Avar validators2 = validator_default.validators;%0Avar Axios = class {%0A constructor(instanceConfig) {%0A this.defaults = instanceConfig;%0A this.interceptors = {%0A request: new InterceptorManager_default(),%0A response: new InterceptorManager_default()%0A };%0A }%0A /**%0A * Dispatch a request%0A *%0A * @param {String|Object} configOrUrl The config specific for this request (merged with this.defaults)%0A * @param {?Object} config%0A *%0A * @returns {Promise} The Promise to be fulfilled%0A */%0A request(configOrUrl, config) {%0A if (typeof configOrUrl === "string") {%0A config = config || {};%0A config.url = configOrUrl;%0A } else {%0A config = configOrUrl || {};%0A }%0A config = mergeConfig(this.defaults, config);%0A const { transitional: transitional2, paramsSerializer, headers } = config;%0A if (transitional2 !== void 0) {%0A validator_default.assertOptions(transitional2, {%0A silentJSONParsing: validators2.transitional(validators2.boolean),%0A forcedJSONParsing: validators2.transitional(validators2.boolean),%0A clarifyTimeoutError: validators2.transitional(validators2.boolean)%0A }, false);%0A }%0A if (paramsSerializer != null) {%0A if (utils_default.isFunction(paramsSerializer)) {%0A config.paramsSerializer = {%0A serialize: paramsSerializer%0A };%0A } else {%0A validator_default.assertOptions(paramsSerializer, {%0A encode: validators2.function,%0A serialize: validators2.function%0A }, true);%0A }%0A }%0A config.method = (config.method || this.defaults.method || "get").toLowerCase();%0A let contextHeaders;%0A contextHeaders = headers && utils_default.merge(%0A headers.common,%0A headers[config.method]%0A );%0A contextHeaders && utils_default.forEach(%0A ["delete", "get", "head", "post", "put", "patch", "common"],%0A (method) => {%0A delete headers[method];%0A }%0A );%0A config.headers = AxiosHeaders_default.concat(contextHeaders, headers);%0A const requestInterceptorChain = [];%0A let synchronousRequestInterceptors = true;%0A this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {%0A if (typeof interceptor.runWhen === "function" && interceptor.runWhen(config) === false) {%0A return;%0A }%0A synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;%0A requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);%0A });%0A const responseInterceptorChain = [];%0A this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {%0A responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);%0A });%0A let promise;%0A let i = 0;%0A let len;%0A if (!synchronousRequestInterceptors) {%0A const chain = [dispatchRequest.bind(this), void 0];%0A chain.unshift.apply(chain, requestInterceptorChain);%0A chain.push.apply(chain, responseInterceptorChain);%0A len = chain.length;%0A promise = Promise.resolve(config);%0A while (i < len) {%0A promise = promise.then(chain[i++], chain[i++]);%0A }%0A return promise;%0A }%0A len = requestInterceptorChain.length;%0A let newConfig = config;%0A i = 0;%0A while (i < len) {%0A const onFulfilled = requestInterceptorChain[i++];%0A const onRejected = requestInterceptorChain[i++];%0A try {%0A newConfig = onFulfilled(newConfig);%0A } catch (error) {%0A onRejected.call(this, error);%0A break;%0A }%0A }%0A try {%0A promise = dispatchRequest.call(this, newConfig);%0A } catch (error) {%0A return Promise.reject(error);%0A }%0A i = 0;%0A len = responseInterceptorChain.length;%0A while (i < len) {%0A promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++]);%0A }%0A return promise;%0A }%0A getUri(config) {%0A config = mergeConfig(this.defaults, config);%0A const fullPath = buildFullPath(config.baseURL, config.url);%0A return buildURL(fullPath, config.params, config.paramsSerializer);%0A }%0A};%0Autils_default.forEach(["delete", "get", "head", "options"], function forEachMethodNoData2(method) {%0A Axios.prototype[method] = function(url, config) {%0A return this.request(mergeConfig(config || {}, {%0A method,%0A url,%0A data: (config || {}).data%0A }));%0A };%0A});%0Autils_default.forEach(["post", "put", "patch"], function forEachMethodWithData2(method) {%0A function generateHTTPMethod(isForm) {%0A return function httpMethod(url, data, config) {%0A return this.request(mergeConfig(config || {}, {%0A method,%0A headers: isForm ? {%0A "Content-Type": "multipart/form-data"%0A } : {},%0A url,%0A data%0A }));%0A };%0A }%0A Axios.prototype[method] = generateHTTPMethod();%0A Axios.prototype[method + "Form"] = generateHTTPMethod(true);%0A});%0Avar Axios_default = Axios;%0A%0A// node_modules/axios/lib/cancel/CancelToken.js%0Avar CancelToken = class _CancelToken {%0A constructor(executor) {%0A if (typeof executor !== "function") {%0A throw new TypeError("executor must be a function.");%0A }%0A let resolvePromise;%0A this.promise = new Promise(function promiseExecutor(resolve) {%0A resolvePromise = resolve;%0A });%0A const token = this;%0A this.promise.then((cancel) => {%0A if (!token._listeners)%0A return;%0A let i = token._listeners.length;%0A while (i-- > 0) {%0A token._listeners[i](cancel);%0A }%0A token._listeners = null;%0A });%0A this.promise.then = (onfulfilled) => {%0A let _resolve;%0A const promise = new Promise((resolve) => {%0A token.subscribe(resolve);%0A _resolve = resolve;%0A }).then(onfulfilled);%0A promise.cancel = function reject() {%0A token.unsubscribe(_resolve);%0A };%0A return promise;%0A };%0A executor(function cancel(message, config, request) {%0A if (token.reason) {%0A return;%0A }%0A token.reason = new CanceledError_default(message, config, request);%0A resolvePromise(token.reason);%0A });%0A }%0A /**%0A * Throws a `CanceledError` if cancellation has been requested.%0A */%0A throwIfRequested() {%0A if (this.reason) {%0A throw this.reason;%0A }%0A }%0A /**%0A * Subscribe to the cancel signal%0A */%0A subscribe(listener) {%0A if (this.reason) {%0A listener(this.reason);%0A return;%0A }%0A if (this._listeners) {%0A this._listeners.push(listener);%0A } else {%0A this._listeners = [listener];%0A }%0A }%0A /**%0A * Unsubscribe from the cancel signal%0A */%0A unsubscribe(listener) {%0A if (!this._listeners) {%0A return;%0A }%0A const index = this._listeners.indexOf(listener);%0A if (index !== -1) {%0A this._listeners.splice(index, 1);%0A }%0A }%0A /**%0A * Returns an object that contains a new `CancelToken` and a function that, when called,%0A * cancels the `CancelToken`.%0A */%0A static source() {%0A let cancel;%0A const token = new _CancelToken(function executor(c) {%0A cancel = c;%0A });%0A return {%0A token,%0A cancel%0A };%0A }%0A};%0Avar CancelToken_default = CancelToken;%0A%0A// node_modules/axios/lib/helpers/spread.js%0Afunction spread(callback) {%0A return function wrap(arr) {%0A return callback.apply(null, arr);%0A };%0A}%0A%0A// node_modules/axios/lib/helpers/isAxiosError.js%0Afunction isAxiosError(payload) {%0A return utils_default.isObject(payload) && payload.isAxiosError === true;%0A}%0A%0A// node_modules/axios/lib/helpers/HttpStatusCode.js%0Avar HttpStatusCode = {%0A Continue: 100,%0A SwitchingProtocols: 101,%0A Processing: 102,%0A EarlyHints: 103,%0A Ok: 200,%0A Created: 201,%0A Accepted: 202,%0A NonAuthoritativeInformation: 203,%0A NoContent: 204,%0A ResetContent: 205,%0A PartialContent: 206,%0A MultiStatus: 207,%0A AlreadyReported: 208,%0A ImUsed: 226,%0A MultipleChoices: 300,%0A MovedPermanently: 301,%0A Found: 302,%0A SeeOther: 303,%0A NotModified: 304,%0A UseProxy: 305,%0A Unused: 306,%0A TemporaryRedirect: 307,%0A PermanentRedirect: 308,%0A BadRequest: 400,%0A Unauthorized: 401,%0A PaymentRequired: 402,%0A Forbidden: 403,%0A NotFound: 404,%0A MethodNotAllowed: 405,%0A NotAcceptable: 406,%0A ProxyAuthenticationRequired: 407,%0A RequestTimeout: 408,%0A Conflict: 409,%0A Gone: 410,%0A LengthRequired: 411,%0A PreconditionFailed: 412,%0A PayloadTooLarge: 413,%0A UriTooLong: 414,%0A UnsupportedMediaType: 415,%0A RangeNotSatisfiable: 416,%0A ExpectationFailed: 417,%0A ImATeapot: 418,%0A MisdirectedRequest: 421,%0A UnprocessableEntity: 422,%0A Locked: 423,%0A FailedDependency: 424,%0A TooEarly: 425,%0A UpgradeRequired: 426,%0A PreconditionRequired: 428,%0A TooManyRequests: 429,%0A RequestHeaderFieldsTooLarge: 431,%0A UnavailableForLegalReasons: 451,%0A InternalServerError: 500,%0A NotImplemented: 501,%0A BadGateway: 502,%0A ServiceUnavailable: 503,%0A GatewayTimeout: 504,%0A HttpVersionNotSupported: 505,%0A VariantAlsoNegotiates: 506,%0A InsufficientStorage: 507,%0A LoopDetected: 508,%0A NotExtended: 510,%0A NetworkAuthenticationRequired: 511%0A};%0AObject.entries(HttpStatusCode).forEach(([key, value]) => {%0A HttpStatusCode[value] = key;%0A});%0Avar HttpStatusCode_default = HttpStatusCode;%0A%0A// node_modules/axios/lib/axios.js%0Afunction createInstance(defaultConfig) {%0A const context = new Axios_default(defaultConfig);%0A const instance2 = bind(Axios_default.prototype.request, context);%0A utils_default.extend(instance2, Axios_default.prototype, context, { allOwnKeys: true });%0A utils_default.extend(instance2, context, null, { allOwnKeys: true });%0A instance2.create = function create(instanceConfig) {%0A return createInstance(mergeConfig(defaultConfig, instanceConfig));%0A };%0A return instance2;%0A}%0Avar axios = createInstance(defaults_default);%0Aaxios.Axios = Axios_default;%0Aaxios.CanceledError = CanceledError_default;%0Aaxios.CancelToken = CancelToken_default;%0Aaxios.isCancel = isCancel;%0Aaxios.VERSION = VERSION;%0Aaxios.toFormData = toFormData_default;%0Aaxios.AxiosError = AxiosError_default;%0Aaxios.Cancel = axios.CanceledError;%0Aaxios.all = function all(promises) {%0A return Promise.all(promises);%0A};%0Aaxios.spread = spread;%0Aaxios.isAxiosError = isAxiosError;%0Aaxios.mergeConfig = mergeConfig;%0Aaxios.AxiosHeaders = AxiosHeaders_default;%0Aaxios.formToJSON = (thing) => formDataToJSON_default(utils_default.isHTMLForm(thing) ? new FormData(thing) : thing);%0Aaxios.HttpStatusCode = HttpStatusCode_default;%0Aaxios.default = axios;%0Avar axios_default = axios;%0A%0A// node_modules/axios/index.js%0Avar {%0A Axios: Axios2,%0A AxiosError: AxiosError2,%0A CanceledError: CanceledError2,%0A isCancel: isCancel2,%0A CancelToken: CancelToken2,%0A VERSION: VERSION2,%0A all: all2,%0A Cancel,%0A isAxiosError: isAxiosError2,%0A spread: spread2,%0A toFormData: toFormData2,%0A AxiosHeaders: AxiosHeaders2,%0A HttpStatusCode: HttpStatusCode2,%0A formToJSON,%0A mergeConfig: mergeConfig2%0A} = axios_default;%0A%0A// node_modules/@thewtex/zstddec/dist/zstddec.modern.js%0Avar init;%0Avar instance;%0Avar heap;%0Avar IMPORT_OBJECT = {%0A env: {%0A emscripten_notify_memory_growth: function(index) {%0A heap = new Uint8Array(instance.exports.memory.buffer);%0A }%0A }%0A};%0Avar ZSTDDecoder = class {%0A init() {%0A if (init)%0A return init;%0A if (typeof fetch !== "undefined") {%0A init = fetch("data:application/wasm;base64," + wasm).then((response) => response.arrayBuffer()).then((arrayBuffer) => WebAssembly.instantiate(arrayBuffer, IMPORT_OBJECT)).then(this._init);%0A } else {%0A init = WebAssembly.instantiate(Buffer.from(wasm, "base64"), IMPORT_OBJECT).then(this._init);%0A }%0A return init;%0A }%0A _init(result) {%0A instance = result.instance;%0A IMPORT_OBJECT.env.emscripten_notify_memory_growth(0);%0A }%0A decode(array, uncompressedSize = 0) {%0A if (!instance)%0A throw new Error(`ZSTDDecoder: Await .init() before decoding.`);%0A const compressedSize = array.byteLength;%0A const compressedPtr = instance.exports.malloc(compressedSize);%0A heap.set(array, compressedPtr);%0A uncompressedSize = uncompressedSize || Number(instance.exports.ZSTD_findDecompressedSize(compressedPtr, compressedSize));%0A const uncompressedPtr = instance.exports.malloc(uncompressedSize);%0A const actualSize = instance.exports.ZSTD_decompress(uncompressedPtr, uncompressedSize, compressedPtr, compressedSize);%0A const dec = heap.slice(uncompressedPtr, uncompressedPtr + actualSize);%0A instance.exports.free(compressedPtr);%0A instance.exports.free(uncompressedPtr);%0A return dec;%0A }%0A};%0Avar wasm = "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IARrdnE2AgAgARAPGiAAIAJBCGo2AgQLzgEBBn9Bun8hCgJAIAIoAgQiCCACKAIAIglqIg0gASAAa0sNAEFsIQogCSAEIAMoAgAiC2tLDQAgACAJaiIEIAIoAggiDGshAiAAIAFBIGsiACALIAlBABAgIAMgCSALajYCAAJAAkAgBCAFayAMTwRAIAIhBQwBCyAMIAQgBmtLDQIgByAHIAIgBWsiAmoiASAIak8EQCAEIAEgCBAKGgwCCyACIAhqIQggBCABQQAgAmsQCiACayEECyAEIAAgBSAIQQEQIAsgDSEKCyAKC8cEAQJ/IAAgA2ohBgJAIANBB0wEQANAIAAgBk8NAiAAIAItAAA6AAAgAEEBaiEAIAJBAWohAgwACwALIARBAUYEQAJAIAAgAmsiBUEHTQRAIAAgAi0AADoAACAAIAItAAE6AAEgACACLQACOgACIAAgAi0AAzoAAyAAIAIgBUECdCIFQcAeaigCAGoiAigAADYABCACIAVB4B5qKAIAayECDAELIAAgAikAADcAAAsgAkEIaiECIABBCGohAAsgASAGTwRAIAAgA2ohASAEQQFHIAAgAmtBD0pyRQRAA0AgACACKQAANwAAIAJBCGohAiAAQQhqIgAgAUkNAAwDCwALIAAgAikAADcAACAAIAIpAAg3AAggA0ERSQ0BIABBEGohAANAIAAgAikAEDcAACAAIAIpABg3AAggACACKQAgNwAQIAAgAikAKDcAGCACQSBqIQIgAEEgaiIAIAFJDQALDAELAkAgACABSwRAIAAhAQwBCyABIABrIQUCQCAEQQFHIAAgAmtBD0pyRQRAIAIhAwNAIAAgAykAADcAACADQQhqIQMgAEEIaiIAIAFJDQALDAELIAAgAikAADcAACAAIAIpAAg3AAggBUERSA0AIABBEGohACACIQMDQCAAIAMpABA3AAAgACADKQAYNwAIIAAgAykAIDcAECAAIAMpACg3ABggA0EgaiEDIABBIGoiACABSQ0ACwsgAiAFaiECCwNAIAEgBk8NASABIAItAAA6AAAgAUEBaiEBIAJBAWohAgwACwALC64HAgV/AX4jAEGAAWsiESQAIBEgAzYCfEF/IQ8CQAJAAkACQAJAIAIOBAEAAwIECyAGRQRAQbh/IQ8MBAtBbCEPIAUtAAAiAiADSw0DIAggAkEC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IAggH2shBgNAAkAgBiAPTgRAQQAhAwNAIANBA0YNAiAFIANBAnQiAmpBrNABaiACIARqKAJkNgIAIANBAWohAwwACwALAkACQAJAIAQoAtwBIgMgBEHwAGogBkEHcUEMbGoiCCgCACIMaiIQIBdLDQAgByAIKAIEIgsgDGoiCmogIUsNACAKQSBqIBYgB2tNDQELIAQgCCgCCDYCKCAEIAgpAgA3AyAgByAWIARBIGogBEHcAWogFyASIBggGhAfIQoMAQsgByAMaiECIAgoAgghCCAHIAMpAAA3AAAgByADKQAINwAIAkAgDEERSQ0AIAcgAykAEDcAECAHIAMpABg3ABggDEEQa0ERSA0AIANBEGohAyAHQSBqIQwDQCAMIAMpABA3AAAgDCADKQAYNwAIIAwgAykAIDcAECAMIAMpACg3ABggA0EgaiEDIAxBIGoiDCACSQ0ACwsgAiAIayEDIAQgEDYC3AEgAiASayAISQRAIAggAiAYa0sNByAaIBogAyASayIDaiIMIAtqTwRAIAIgDCALEAoaDAILIAMgC2ohCyACIAxBACADaxAKIANrIQIgEiEDCyAIQRBPBEAgAiADKQAANwAAIAIgAykACDcACCALQRFIDQEgAiALaiEIIAJBEGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAhJDQALDAELAkAgCEEHTQRAIAIgAy0AADoAACACIAMtAAE6AAEgAiADLQACOgACIAIgAy0AAzoAAyACIAMgCEECdCIIQcAeaigCAGoiAygAADYABCADIAhB4B5qKAIAayEDDAELIAIgAykAADcAAAsgC0EJSQ0AIAIgC2ohDCACQQhqIgggA0EIaiIDa0EPTARAA0AgCCADKQAANwAAIANBCGohAyAIQQhqIgggDEkNAAwCCwALIAggAykAADcAACAIIAMpAAg3AAggC0EZSA0AIAJBGGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAxJDQALCyAKQYh/SwRAIAohCQwGBSAGQQFqIQYgByAKaiEHDAILAAsLIAQoAtwBIQMLQbp/IQkgFyADayICIBYgB2tLDQIgBwR/IAcgAyACEAIgAmoFQQALIA5rIQkMAgsgBUEANgKc6wELIAQgBSgC8OoBIgM2AtwBIAkgDmohDCADIAUoAoDrAWohEAJAIA9FBEAgDiEGDAELIAUoArjpASENIAUoArTpASETIAUoArDpASESIAVBATYChOoBQQAhAwNAIANBA0cEQCAEIANBAnQiAmogAiAFakGs0AFqKAIANgKcASADQQFqIQMMAQsLQWwhCSAEQfAAaiICIAcgBhANQYh/Sw0BIDEgAiAFKAIAEB4gMCACIAUoAggQHiAvIAIgBSgCBBAeIAxBIGshGCAOIQYDQCAEKAKIASAEKAKEAUEDdGopAgAiQKciCkEQdiIZQf8BcSELIAQoApgBIAQoApQBQQN0aikCACJBpyIWQRB2Ih9B/wFxIRogBCgCkAEgBCgCjAFBA3RqKQIAIkJCIIinIQcgQUIgiCBAQiCIpyEDAkAgQkIQiKciCEH/AXEiAkECTwRAAkAgAkEZSSA/QoGAgBBUckUEQCAEQSAgBCgCdCIIayIRIAIgAiARSxsiFyAIajYCdCAHIAQoAnAgCHRBACAXa3YgAiAXayIXdGohCCAEQfAAahAPGiACIBFNDQEgBCAEKAJ0IgIgF2o2AnQgBCgCcCACdEEAIBdrdiAIaiEIDAELIAQgAiAEKAJ0IhFqNgJ0IAQoAnAgEXRBACAIa3YgB2ohCCAEQfAAahAPGgsgBCkCnAEhRCAEIAg2ApwBIAQgRDcCoAEMAQsCQCACRQRAIAMEQCAEKAKcASEIDAMLIAQoAqABIQgMAQsgBCAEKAJ0IgJBAWo2AnQCfyAHIANFaiAEKAJwIAJ0QR92aiICQQNGBEAgBCgCnAFBAWsMAQsgAkECdCAEaigCnAELIgdFIAdqIQggAkEBRwRAIAQgBCgCoAE2AqQBCwsgBCAEKAKcATYCoAEgBCAINgKcAQunIQIgQUKAgPwHg1BFBEAgBCAEKAJ0IgcgGmo2AnQgBCgCcCAHdEEAIB9rdiACaiECCyALIBpqQRRPBEAgBEHwAGoQDxoLIEBCgID8B4NQRQRAIAQgBCgCdCIHIAtqNgJ0IAQoAnAgB3RBACAZa3YgA2ohAwsgBEHwAGoQDxogBCAEKAJwIgdBACAKQRh2IgsgBCgCdGoiGmt2IAtBAnRBoB1qKAIAcSAKQf//A3FqNgKEASAEIBogFkEYdiIKaiILNgJ0IAQgCkECdEGgHWooAgAgB0EAIAtrdnEgFkH//wNxajYClAEgBEHwAGoQDxogBCBCpyIHQRh2IgogBCgCdGoiCzYCdCAEIApBAnRBoB1qKAIAIAQoAnBBACALa3ZxIAdB//8DcWo2AowBIAQgAzYCOCAEIAI2AjwgBCAINgJAAkACQAJAIAQoAtwBIgsgA2oiFiAQSw0AIAYgAiADaiIKaiAYSw0AIApBIGogDCAGa00NAQsgBCAEQUBrKAIANgIIIAQgBCkDODcDACAGIAwgBCAEQdwBaiAQIBIgEyANEB8hCgwBCyADIAZqIQcgBiALKQAANwAAIAYgCykACDcACAJAIANBEUkNACAGIAspABA3ABAgBiALKQAYNwAYIANBEGtBEUgNACALQRBqIQMgBkEgaiELA0AgCyADKQAQNwAAIAsgAykAGDcACCALIAMpACA3ABAgCyADKQAoNwAYIANBIGohAyALQSBqIgsgB0kNAAsLIAcgCGshAyAEIBY2AtwBIAcgEmsgCEkEQCAIIAcgE2tLDQQgDSANIAMgEmsiA2oiCyACak8EQCAHIAsgAhAKGgwCCyAHIAtBACADaxAKIAQgAiADaiICNgI8IANrIQcgEiEDCyAIQRBPBEAgByADKQAANwAAIAcgAykACDcACCACQRFIDQEgAiAHaiEIIAdBEGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAhJDQALDAELAkAgCEEHTQRAIAcgAy0AADoAACAHIAMtAAE6AAEgByADLQACOgACIAcgAy0AAzoAAyAHIAMgCEECdCIIQcAeaigCAGoiAygAADYABCADIAhB4B5qKAIAayEDDAELIAcgAykAADcAAAsgAkEJSQ0AIAIgB2ohCyAHQQhqIgggA0EIaiIDa0EPTARAA0AgCCADKQAANwAAIANBCGohAyAIQQhqIgggC0kNAAwCCwALIAggAykAADcAACAIIAMpAAg3AAggAkEZSA0AIAdBGGohAgNAIAIgAykAEDcAACACIAMpABg3AAggAiADKQAgNwAQIAIgAykAKDcAGCADQSBqIQMgAkEgaiICIAtJDQALCyAKQYh/SwRAIAohCQwDCyAGIApqIQYgBEHwAGoQDyEDIA9B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";%0A%0A// dist/core/internal/loadEmscriptenModuleWebWorker.js%0Avar decoder = new ZSTDDecoder();%0Avar decoderInitialized = false;%0Aasync function loadEmscriptenModuleWebWorker(moduleRelativePathOrURL, baseUrl) {%0A let modulePrefix = null;%0A if (typeof moduleRelativePathOrURL !== "string") {%0A modulePrefix = moduleRelativePathOrURL.href;%0A } else if (moduleRelativePathOrURL.startsWith("http")) {%0A modulePrefix = moduleRelativePathOrURL;%0A } else {%0A modulePrefix = `${baseUrl}/${moduleRelativePathOrURL}`;%0A }%0A if (modulePrefix.endsWith(".js")) {%0A modulePrefix = modulePrefix.substring(0, modulePrefix.length - 3);%0A }%0A if (modulePrefix.endsWith(".wasm")) {%0A modulePrefix = modulePrefix.substring(0, modulePrefix.length - 5);%0A }%0A const wasmBinaryPath = `${modulePrefix}.wasm`;%0A const response = await axios_default.get(`${wasmBinaryPath}.zst`, { responseType: "arraybuffer" });%0A if (!decoderInitialized) {%0A await decoder.init();%0A decoderInitialized = true;%0A }%0A const decompressedArray = decoder.decode(new Uint8Array(response.data));%0A const wasmBinary = decompressedArray.buffer;%0A const modulePath = `${modulePrefix}.js`;%0A const result = await import(%0A /* webpackIgnore: true */%0A /* @vite-ignore */%0A modulePath%0A );%0A const emscriptenModule = result.default({ wasmBinary });%0A return emscriptenModule;%0A}%0Avar loadEmscriptenModuleWebWorker_default = loadEmscriptenModuleWebWorker;%0A%0A// dist/core/web-workers/load-pipeline-module.js%0Avar pipelineToModule = /* @__PURE__ */ new Map();%0Aasync function loadPipelineModule(pipelinePath, baseUrl) {%0A let moduleRelativePathOrURL = pipelinePath;%0A let pipeline = pipelinePath;%0A let pipelineModule = null;%0A if (typeof pipelinePath !== "string") {%0A moduleRelativePathOrURL = new URL(pipelinePath.href);%0A pipeline = moduleRelativePathOrURL.href;%0A }%0A if (pipelineToModule.has(pipeline)) {%0A pipelineModule = pipelineToModule.get(pipeline);%0A } else {%0A pipelineToModule.set(pipeline, await loadEmscriptenModuleWebWorker_default(moduleRelativePathOrURL, baseUrl));%0A pipelineModule = pipelineToModule.get(pipeline);%0A }%0A return pipelineModule;%0A}%0Avar load_pipeline_module_default = loadPipelineModule;%0A%0A// dist/io/internal/MimeToImageIO.js%0Avar mimeToIO = /* @__PURE__ */ new Map([%0A ["image/jpeg", "JPEGImageIO"],%0A ["image/png", "PNGImageIO"],%0A ["image/tiff", "TIFFImageIO"],%0A ["image/x-ms-bmp", "BMPImageIO"],%0A ["image/x-bmp", "BMPImageIO"],%0A ["image/bmp", "BMPImageIO"],%0A ["application/dicom", "GDCMImageIO"]%0A]);%0Avar MimeToImageIO_default = mimeToIO;%0A%0A// dist/io/extensionToImageIO.js%0Avar extensionToIO = /* @__PURE__ */ new Map([%0A ["bmp", "BMPImageIO"],%0A ["BMP", "BMPImageIO"],%0A ["dcm", "GDCMImageIO"],%0A ["DCM", "GDCMImageIO"],%0A ["gipl", "GiplImageIO"],%0A ["gipl.gz", "GiplImageIO"],%0A ["hdf5", "HDF5ImageIO"],%0A ["jpg", "JPEGImageIO"],%0A ["JPG", "JPEGImageIO"],%0A ["jpeg", "JPEGImageIO"],%0A ["JPEG", "JPEGImageIO"],%0A ["iwi", "WasmImageIO"],%0A ["iwi.cbor", "WasmImageIO"],%0A ["iwi.cbor.zst", "WasmZstdImageIO"],%0A ["lsm", "LSMImageIO"],%0A ["mnc", "MINCImageIO"],%0A ["MNC", "MINCImageIO"],%0A ["mnc.gz", "MINCImageIO"],%0A ["MNC.GZ", "MINCImageIO"],%0A ["mnc2", "MINCImageIO"],%0A ["MNC2", "MINCImageIO"],%0A ["mgh", "MGHImageIO"],%0A ["mgz", "MGHImageIO"],%0A ["mgh.gz", "MGHImageIO"],%0A ["mha", "MetaImageIO"],%0A ["mhd", "MetaImageIO"],%0A ["mrc", "MRCImageIO"],%0A ["nia", "NiftiImageIO"],%0A ["nii", "NiftiImageIO"],%0A ["nii.gz", "NiftiImageIO"],%0A ["hdr", "NiftiImageIO"],%0A ["nrrd", "NrrdImageIO"],%0A ["NRRD", "NrrdImageIO"],%0A ["nhdr", "NrrdImageIO"],%0A ["NHDR", "NrrdImageIO"],%0A ["png", "PNGImageIO"],%0A ["PNG", "PNGImageIO"],%0A ["pic", "BioRadImageIO"],%0A ["PIC", "BioRadImageIO"],%0A ["tif", "TIFFImageIO"],%0A ["TIF", "TIFFImageIO"],%0A ["tiff", "TIFFImageIO"],%0A ["TIFF", "TIFFImageIO"],%0A ["vtk", "VTKImageIO"],%0A ["VTK", "VTKImageIO"],%0A ["isq", "ScancoImageIO"],%0A ["ISQ", "ScancoImageIO"],%0A ["fdf", "FDFImageIO"],%0A ["FDF", "FDFImageIO"]%0A]);%0Avar extensionToImageIO_default = extensionToIO;%0A%0A// dist/io/getFileExtension.js%0Afunction getFileExtension(filePath) {%0A let extension = filePath.slice((filePath.lastIndexOf(".") - 1 >>> 0) + 2);%0A if (extension.toLowerCase() === "gz") {%0A const index = filePath.slice(0, -3).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A } else if (extension.toLowerCase() === "cbor") {%0A const index = filePath.slice(0, -5).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A } else if (extension.toLowerCase() === "zst") {%0A const index = filePath.slice(0, -10).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A } else if (extension.toLowerCase() === "zip") {%0A const index = filePath.slice(0, -4).lastIndexOf(".");%0A extension = filePath.slice((index - 1 >>> 0) + 2);%0A }%0A return extension;%0A}%0Avar getFileExtension_default = getFileExtension;%0A%0A// dist/io/internal/ImageIOIndex.js%0Avar ImageIOIndex = ["PNGImageIO", "MetaImageIO", "TIFFImageIO", "NiftiImageIO", "JPEGImageIO", "NrrdImageIO", "VTKImageIO", "BMPImageIO", "HDF5ImageIO", "MINCImageIO", "MRCImageIO", "LSMImageIO", "MGHImageIO", "BioRadImageIO", "GiplImageIO", "GEAdwImageIO", "GE4ImageIO", "GE5ImageIO", "GDCMImageIO", "ScancoImageIO", "FDFImageIO", "WasmImageIO", "WasmZstdImageIO"];%0Avar ImageIOIndex_default = ImageIOIndex;%0A%0A// dist/core/InterfaceTypes.js%0Avar InterfaceTypes = {%0A // Todo: remove Interface prefix after IOTypes has been removed%0A TextFile: "InterfaceTextFile",%0A BinaryFile: "InterfaceBinaryFile",%0A TextStream: "InterfaceTextStream",%0A BinaryStream: "InterfaceBinaryStream",%0A Image: "InterfaceImage",%0A Mesh: "InterfaceMesh",%0A PolyData: "InterfacePolyData",%0A JsonCompatible: "InterfaceJsonCompatible"%0A};%0Avar InterfaceTypes_default = InterfaceTypes;%0A%0A// dist/core/IOTypes.js%0Avar IOTypes = {%0A Text: "Text",%0A Binary: "Binary",%0A Image: "Image",%0A Mesh: "Mesh"%0A};%0Avar IOTypes_default = IOTypes;%0A%0A// dist/core/interface-types/int-types.js%0Avar IntTypes = {%0A Int8: "int8",%0A UInt8: "uint8",%0A Int16: "int16",%0A UInt16: "uint16",%0A Int32: "int32",%0A UInt32: "uint32",%0A Int64: "int64",%0A UInt64: "uint64",%0A SizeValueType: "uint64",%0A IdentifierType: "uint64",%0A IndexValueType: "int64",%0A OffsetValueType: "int64"%0A};%0Avar int_types_default = IntTypes;%0A%0A// dist/core/interface-types/float-types.js%0Avar FloatTypes = {%0A Float32: "float32",%0A Float64: "float64",%0A SpacePrecisionType: "float64"%0A};%0Avar float_types_default = FloatTypes;%0A%0A// dist/core/bufferToTypedArray.js%0Afunction bufferToTypedArray(wasmType, buffer) {%0A let typedArray = null;%0A switch (wasmType) {%0A case int_types_default.UInt8: {%0A typedArray = new Uint8Array(buffer);%0A break;%0A }%0A case int_types_default.Int8: {%0A typedArray = new Int8Array(buffer);%0A break;%0A }%0A case int_types_default.UInt16: {%0A typedArray = new Uint16Array(buffer);%0A break;%0A }%0A case int_types_default.Int16: {%0A typedArray = new Int16Array(buffer);%0A break;%0A }%0A case int_types_default.UInt32: {%0A typedArray = new Uint32Array(buffer);%0A break;%0A }%0A case int_types_default.Int32: {%0A typedArray = new Int32Array(buffer);%0A break;%0A }%0A case int_types_default.UInt64: {%0A if (typeof globalThis.BigUint64Array === "function") {%0A typedArray = new BigUint64Array(buffer);%0A } else {%0A typedArray = new Uint8Array(buffer);%0A }%0A break;%0A }%0A case int_types_default.Int64: {%0A if (typeof globalThis.BigInt64Array === "function") {%0A typedArray = new BigInt64Array(buffer);%0A } else {%0A typedArray = new Uint8Array(buffer);%0A }%0A break;%0A }%0A case float_types_default.Float32: {%0A typedArray = new Float32Array(buffer);%0A break;%0A }%0A case float_types_default.Float64: {%0A typedArray = new Float64Array(buffer);%0A break;%0A }%0A case "null": {%0A typedArray = null;%0A break;%0A }%0A case null: {%0A typedArray = null;%0A break;%0A }%0A default:%0A throw new Error("Type is not supported as a TypedArray");%0A }%0A return typedArray;%0A}%0Avar bufferToTypedArray_default = bufferToTypedArray;%0A%0A// dist/pipeline/internal/runPipelineEmscripten.js%0Avar haveSharedArrayBuffer = typeof globalThis.SharedArrayBuffer === "function";%0Avar encoder = new TextEncoder();%0Avar decoder2 = new TextDecoder("utf-8");%0Afunction readFileSharedArray(emscriptenModule, path) {%0A const opts = { flags: "r", encoding: "binary" };%0A const stream = emscriptenModule.fs_open(path, opts.flags);%0A const stat = emscriptenModule.fs_stat(path);%0A const length = stat.size;%0A let arrayBufferData = null;%0A if (haveSharedArrayBuffer) {%0A arrayBufferData = new SharedArrayBuffer(length);%0A } else {%0A arrayBufferData = new ArrayBuffer(length);%0A }%0A const array = new Uint8Array(arrayBufferData);%0A emscriptenModule.fs_read(stream, array, 0, length, 0);%0A emscriptenModule.fs_close(stream);%0A return array;%0A}%0Afunction memoryUint8SharedArray(emscriptenModule, byteOffset, length) {%0A let arrayBufferData = null;%0A if (haveSharedArrayBuffer) {%0A arrayBufferData = new SharedArrayBuffer(length);%0A } else {%0A arrayBufferData = new ArrayBuffer(length);%0A }%0A const array = new Uint8Array(arrayBufferData);%0A const dataArrayView = new Uint8Array(emscriptenModule.HEAPU8.buffer, byteOffset, length);%0A array.set(dataArrayView);%0A return array;%0A}%0Afunction setPipelineModuleInputArray(emscriptenModule, dataArray, inputIndex, subIndex) {%0A let dataPtr = 0;%0A if (dataArray !== null) {%0A dataPtr = emscriptenModule.ccall("itk_wasm_input_array_alloc", "number", ["number", "number", "number", "number"], [0, inputIndex, subIndex, dataArray.buffer.byteLength]);%0A emscriptenModule.HEAPU8.set(new Uint8Array(dataArray.buffer), dataPtr);%0A }%0A return dataPtr;%0A}%0Afunction setPipelineModuleInputJSON(emscriptenModule, dataObject, inputIndex) {%0A const dataJSON = JSON.stringify(dataObject);%0A const jsonPtr = emscriptenModule.ccall("itk_wasm_input_json_alloc", "number", ["number", "number", "number"], [0, inputIndex, dataJSON.length]);%0A emscriptenModule.writeAsciiToMemory(dataJSON, jsonPtr, false);%0A}%0Afunction getPipelineModuleOutputArray(emscriptenModule, outputIndex, subIndex, componentType) {%0A const dataPtr = emscriptenModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, outputIndex, subIndex]);%0A const dataSize = emscriptenModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, outputIndex, subIndex]);%0A const dataUint8 = memoryUint8SharedArray(emscriptenModule, dataPtr, dataSize);%0A const data = bufferToTypedArray_default(componentType, dataUint8.buffer);%0A return data;%0A}%0Afunction getPipelineModuleOutputJSON(emscriptenModule, outputIndex) {%0A const jsonPtr = emscriptenModule.ccall("itk_wasm_output_json_address", "number", ["number", "number"], [0, outputIndex]);%0A const dataJSON = emscriptenModule.AsciiToString(jsonPtr);%0A const dataObject = JSON.parse(dataJSON);%0A return dataObject;%0A}%0Afunction runPipelineEmscripten(pipelineModule, args, outputs, inputs) {%0A if (!(inputs == null) && inputs.length > 0) {%0A inputs.forEach(function(input, index) {%0A var _a;%0A switch (input.type) {%0A case InterfaceTypes_default.TextStream: {%0A const dataArray = encoder.encode(input.data.data);%0A const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0);%0A const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` };%0A setPipelineModuleInputJSON(pipelineModule, dataJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.JsonCompatible: {%0A const dataArray = encoder.encode(JSON.stringify(input.data));%0A const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0);%0A const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` };%0A setPipelineModuleInputJSON(pipelineModule, dataJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.BinaryStream: {%0A const dataArray = input.data.data;%0A const arrayPtr = setPipelineModuleInputArray(pipelineModule, dataArray, index, 0);%0A const dataJSON = { size: dataArray.buffer.byteLength, data: `data:application/vnd.itk.address,0:${arrayPtr}` };%0A setPipelineModuleInputJSON(pipelineModule, dataJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.TextFile: {%0A pipelineModule.fs_writeFile(input.data.path, input.data.data);%0A break;%0A }%0A case InterfaceTypes_default.BinaryFile: {%0A pipelineModule.fs_writeFile(input.data.path, input.data.data);%0A break;%0A }%0A case InterfaceTypes_default.Image: {%0A const image = input.data;%0A const dataPtr = setPipelineModuleInputArray(pipelineModule, image.data, index, 0);%0A const directionPtr = setPipelineModuleInputArray(pipelineModule, image.direction, index, 1);%0A const metadata = typeof ((_a = image.metadata) === null || _a === void 0 ? void 0 : _a.entries) !== "undefined" ? JSON.stringify(Array.from(image.metadata.entries())) : "[]";%0A const imageJSON = {%0A imageType: image.imageType,%0A name: image.name,%0A origin: image.origin,%0A spacing: image.spacing,%0A direction: `data:application/vnd.itk.address,0:${directionPtr}`,%0A size: image.size,%0A data: `data:application/vnd.itk.address,0:${dataPtr}`,%0A metadata%0A };%0A setPipelineModuleInputJSON(pipelineModule, imageJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.Mesh: {%0A const mesh = input.data;%0A const pointsPtr = setPipelineModuleInputArray(pipelineModule, mesh.points, index, 0);%0A const cellsPtr = setPipelineModuleInputArray(pipelineModule, mesh.cells, index, 1);%0A const pointDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.pointData, index, 2);%0A const cellDataPtr = setPipelineModuleInputArray(pipelineModule, mesh.cellData, index, 3);%0A const meshJSON = {%0A meshType: mesh.meshType,%0A name: mesh.name,%0A numberOfPoints: mesh.numberOfPoints,%0A points: `data:application/vnd.itk.address,0:${pointsPtr}`,%0A numberOfCells: mesh.numberOfCells,%0A cells: `data:application/vnd.itk.address,0:${cellsPtr}`,%0A cellBufferSize: mesh.cellBufferSize,%0A numberOfPointPixels: mesh.numberOfPointPixels,%0A pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`,%0A numberOfCellPixels: mesh.numberOfCellPixels,%0A cellData: `data:application/vnd.itk.address,0:${cellDataPtr}`%0A };%0A setPipelineModuleInputJSON(pipelineModule, meshJSON, index);%0A break;%0A }%0A case InterfaceTypes_default.PolyData: {%0A const polyData = input.data;%0A const pointsPtr = setPipelineModuleInputArray(pipelineModule, polyData.points, index, 0);%0A const verticesPtr = setPipelineModuleInputArray(pipelineModule, polyData.vertices, index, 1);%0A const linesPtr = setPipelineModuleInputArray(pipelineModule, polyData.lines, index, 2);%0A const polygonsPtr = setPipelineModuleInputArray(pipelineModule, polyData.polygons, index, 3);%0A const triangleStripsPtr = setPipelineModuleInputArray(pipelineModule, polyData.triangleStrips, index, 4);%0A const pointDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 5);%0A const cellDataPtr = setPipelineModuleInputArray(pipelineModule, polyData.pointData, index, 6);%0A const polyDataJSON = {%0A polyDataType: polyData.polyDataType,%0A name: polyData.name,%0A numberOfPoints: polyData.numberOfPoints,%0A points: `data:application/vnd.itk.address,0:${pointsPtr}`,%0A verticesBufferSize: polyData.verticesBufferSize,%0A vertices: `data:application/vnd.itk.address,0:${verticesPtr}`,%0A linesBufferSize: polyData.linesBufferSize,%0A lines: `data:application/vnd.itk.address,0:${linesPtr}`,%0A polygonsBufferSize: polyData.polygonsBufferSize,%0A polygons: `data:application/vnd.itk.address,0:${polygonsPtr}`,%0A triangleStripsBufferSize: polyData.triangleStripsBufferSize,%0A triangleStrips: `data:application/vnd.itk.address,0:${triangleStripsPtr}`,%0A numberOfPointPixels: polyData.numberOfPointPixels,%0A pointData: `data:application/vnd.itk.address,0:${pointDataPtr}`,%0A numberOfCellPixels: polyData.numberOfCellPixels,%0A cellData: `data:application/vnd.itk.address,0:${cellDataPtr}`%0A };%0A setPipelineModuleInputJSON(pipelineModule, polyDataJSON, index);%0A break;%0A }%0A case IOTypes_default.Text: {%0A pipelineModule.fs_writeFile(input.path, input.data);%0A break;%0A }%0A case IOTypes_default.Binary: {%0A pipelineModule.fs_writeFile(input.path, input.data);%0A break;%0A }%0A case IOTypes_default.Image: {%0A const image = input.data;%0A const imageJSON = {%0A imageType: image.imageType,%0A name: image.name,%0A origin: image.origin,%0A spacing: image.spacing,%0A direction: "data:application/vnd.itk.path,data/direction.raw",%0A size: image.size,%0A data: "data:application/vnd.itk.path,data/data.raw"%0A };%0A pipelineModule.fs_mkdirs(`${input.path}/data`);%0A pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(imageJSON));%0A if (image.data === null) {%0A throw Error("image.data is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/data.raw`, new Uint8Array(image.data.buffer));%0A pipelineModule.fs_writeFile(`${input.path}/data/direction.raw`, new Uint8Array(image.direction.buffer));%0A break;%0A }%0A case IOTypes_default.Mesh: {%0A const mesh = input.data;%0A const meshJSON = {%0A meshType: mesh.meshType,%0A name: mesh.name,%0A numberOfPoints: mesh.numberOfPoints,%0A points: "data:application/vnd.itk.path,data/points.raw",%0A numberOfPointPixels: mesh.numberOfPointPixels,%0A pointData: "data:application/vnd.itk.path,data/pointData.raw",%0A numberOfCells: mesh.numberOfCells,%0A cells: "data:application/vnd.itk.path,data/cells.raw",%0A numberOfCellPixels: mesh.numberOfCellPixels,%0A cellData: "data:application/vnd.itk.path,data/cellData.raw",%0A cellBufferSize: mesh.cellBufferSize%0A };%0A pipelineModule.fs_mkdirs(`${input.path}/data`);%0A pipelineModule.fs_writeFile(`${input.path}/index.json`, JSON.stringify(meshJSON));%0A if (meshJSON.numberOfPoints > 0) {%0A if (mesh.points === null) {%0A throw Error("mesh.points is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/points.raw`, new Uint8Array(mesh.points.buffer));%0A }%0A if (meshJSON.numberOfPointPixels > 0) {%0A if (mesh.pointData === null) {%0A throw Error("mesh.pointData is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/pointData.raw`, new Uint8Array(mesh.pointData.buffer));%0A }%0A if (meshJSON.numberOfCells > 0) {%0A if (mesh.cells === null) {%0A throw Error("mesh.cells is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/cells.raw`, new Uint8Array(mesh.cells.buffer));%0A }%0A if (meshJSON.numberOfCellPixels > 0) {%0A if (mesh.cellData === null) {%0A throw Error("mesh.cellData is null");%0A }%0A pipelineModule.fs_writeFile(`${input.path}/data/cellData.raw`, new Uint8Array(mesh.cellData.buffer));%0A }%0A break;%0A }%0A default:%0A throw Error("Unsupported input InterfaceType");%0A }%0A });%0A }%0A pipelineModule.resetModuleStdout();%0A pipelineModule.resetModuleStderr();%0A const stackPtr = pipelineModule.stackSave();%0A let returnValue = 0;%0A try {%0A returnValue = pipelineModule.callMain(args.slice());%0A } catch (exception) {%0A if (typeof exception === "number") {%0A console.log("Exception while running pipeline:");%0A console.log("stdout:", pipelineModule.getModuleStdout());%0A console.error("stderr:", pipelineModule.getModuleStderr());%0A if (typeof pipelineModule.getExceptionMessage !== "undefined") {%0A console.error("exception:", pipelineModule.getExceptionMessage(exception));%0A } else {%0A console.error("Build module in Debug mode for exception message information.");%0A }%0A }%0A throw exception;%0A } finally {%0A pipelineModule.stackRestore(stackPtr);%0A }%0A const stdout = pipelineModule.getModuleStdout();%0A const stderr = pipelineModule.getModuleStderr();%0A const populatedOutputs = [];%0A if (!(outputs == null) && outputs.length > 0 && returnValue === 0) {%0A outputs.forEach(function(output, index) {%0A let outputData = null;%0A switch (output.type) {%0A case InterfaceTypes_default.TextStream: {%0A const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize);%0A outputData = { data: decoder2.decode(dataArrayView) };%0A break;%0A }%0A case InterfaceTypes_default.JsonCompatible: {%0A const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataArrayView = new Uint8Array(pipelineModule.HEAPU8.buffer, dataPtr, dataSize);%0A outputData = JSON.parse(decoder2.decode(dataArrayView));%0A break;%0A }%0A case InterfaceTypes_default.BinaryStream: {%0A const dataPtr = pipelineModule.ccall("itk_wasm_output_array_address", "number", ["number", "number", "number"], [0, index, 0]);%0A const dataSize = pipelineModule.ccall("itk_wasm_output_array_size", "number", ["number", "number", "number"], [0, index, 0]);%0A outputData = { data: memoryUint8SharedArray(pipelineModule, dataPtr, dataSize) };%0A break;%0A }%0A case InterfaceTypes_default.TextFile: {%0A outputData = { path: output.data.path, data: pipelineModule.fs_readFile(output.data.path, { encoding: "utf8" }) };%0A break;%0A }%0A case InterfaceTypes_default.BinaryFile: {%0A outputData = { path: output.data.path, data: readFileSharedArray(pipelineModule, output.data.path) };%0A break;%0A }%0A case InterfaceTypes_default.Image: {%0A const image = getPipelineModuleOutputJSON(pipelineModule, index);%0A image.data = getPipelineModuleOutputArray(pipelineModule, index, 0, image.imageType.componentType);%0A image.direction = getPipelineModuleOutputArray(pipelineModule, index, 1, float_types_default.Float64);%0A image.metadata = new Map(image.metadata);%0A outputData = image;%0A break;%0A }%0A case InterfaceTypes_default.Mesh: {%0A const mesh = getPipelineModuleOutputJSON(pipelineModule, index);%0A if (mesh.numberOfPoints > 0) {%0A mesh.points = getPipelineModuleOutputArray(pipelineModule, index, 0, mesh.meshType.pointComponentType);%0A } else {%0A mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCells > 0) {%0A mesh.cells = getPipelineModuleOutputArray(pipelineModule, index, 1, mesh.meshType.cellComponentType);%0A } else {%0A mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfPointPixels > 0) {%0A mesh.pointData = getPipelineModuleOutputArray(pipelineModule, index, 2, mesh.meshType.pointPixelComponentType);%0A } else {%0A mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCellPixels > 0) {%0A mesh.cellData = getPipelineModuleOutputArray(pipelineModule, index, 3, mesh.meshType.cellPixelComponentType);%0A } else {%0A mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0));%0A }%0A outputData = mesh;%0A break;%0A }%0A case InterfaceTypes_default.PolyData: {%0A const polyData = getPipelineModuleOutputJSON(pipelineModule, index);%0A if (polyData.numberOfPoints > 0) {%0A polyData.points = getPipelineModuleOutputArray(pipelineModule, index, 0, float_types_default.Float32);%0A } else {%0A polyData.points = new Float32Array();%0A }%0A if (polyData.verticesBufferSize > 0) {%0A polyData.vertices = getPipelineModuleOutputArray(pipelineModule, index, 1, int_types_default.UInt32);%0A } else {%0A polyData.vertices = new Uint32Array();%0A }%0A if (polyData.linesBufferSize > 0) {%0A polyData.lines = getPipelineModuleOutputArray(pipelineModule, index, 2, int_types_default.UInt32);%0A } else {%0A polyData.lines = new Uint32Array();%0A }%0A if (polyData.polygonsBufferSize > 0) {%0A polyData.polygons = getPipelineModuleOutputArray(pipelineModule, index, 3, int_types_default.UInt32);%0A } else {%0A polyData.polygons = new Uint32Array();%0A }%0A if (polyData.triangleStripsBufferSize > 0) {%0A polyData.triangleStrips = getPipelineModuleOutputArray(pipelineModule, index, 4, int_types_default.UInt32);%0A } else {%0A polyData.triangleStrips = new Uint32Array();%0A }%0A if (polyData.numberOfPointPixels > 0) {%0A polyData.pointData = getPipelineModuleOutputArray(pipelineModule, index, 5, polyData.polyDataType.pointPixelComponentType);%0A } else {%0A polyData.pointData = bufferToTypedArray_default(polyData.polyDataType.pointPixelComponentType, new ArrayBuffer(0));%0A }%0A if (polyData.numberOfCellPixels > 0) {%0A polyData.cellData = getPipelineModuleOutputArray(pipelineModule, index, 6, polyData.polyDataType.cellPixelComponentType);%0A } else {%0A polyData.cellData = bufferToTypedArray_default(polyData.polyDataType.cellPixelComponentType, new ArrayBuffer(0));%0A }%0A outputData = polyData;%0A break;%0A }%0A case IOTypes_default.Text: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A outputData = pipelineModule.fs_readFile(output.path, { encoding: "utf8" });%0A break;%0A }%0A case IOTypes_default.Binary: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A outputData = readFileSharedArray(pipelineModule, output.path);%0A break;%0A }%0A case IOTypes_default.Image: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A const imageJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" });%0A const image = JSON.parse(imageJSON);%0A const dataUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/data.raw`);%0A image.data = bufferToTypedArray_default(image.imageType.componentType, dataUint8.buffer);%0A const directionUint8 = readFileSharedArray(pipelineModule, `${output.path}/data/direction.raw`);%0A image.direction = bufferToTypedArray_default(float_types_default.Float64, directionUint8.buffer);%0A outputData = image;%0A break;%0A }%0A case IOTypes_default.Mesh: {%0A if (typeof output.path === "undefined") {%0A throw new Error("output.path not defined");%0A }%0A const meshJSON = pipelineModule.fs_readFile(`${output.path}/index.json`, { encoding: "utf8" });%0A const mesh = JSON.parse(meshJSON);%0A if (mesh.numberOfPoints > 0) {%0A const dataUint8Points = readFileSharedArray(pipelineModule, `${output.path}/data/points.raw`);%0A mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, dataUint8Points.buffer);%0A } else {%0A mesh.points = bufferToTypedArray_default(mesh.meshType.pointComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfPointPixels > 0) {%0A const dataUint8PointData = readFileSharedArray(pipelineModule, `${output.path}/data/pointData.raw`);%0A mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, dataUint8PointData.buffer);%0A } else {%0A mesh.pointData = bufferToTypedArray_default(mesh.meshType.pointPixelComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCells > 0) {%0A const dataUint8Cells = readFileSharedArray(pipelineModule, `${output.path}/data/cells.raw`);%0A mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, dataUint8Cells.buffer);%0A } else {%0A mesh.cells = bufferToTypedArray_default(mesh.meshType.cellComponentType, new ArrayBuffer(0));%0A }%0A if (mesh.numberOfCellPixels > 0) {%0A const dataUint8CellData = readFileSharedArray(pipelineModule, `${output.path}/data/cellData.raw`);%0A mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, dataUint8CellData.buffer);%0A } else {%0A mesh.cellData = bufferToTypedArray_default(mesh.meshType.cellPixelComponentType, new ArrayBuffer(0));%0A }%0A outputData = mesh;%0A break;%0A }%0A default:%0A throw Error("Unsupported output InterfaceType");%0A }%0A const populatedOutput = {%0A type: output.type,%0A data: outputData%0A };%0A populatedOutputs.push(populatedOutput);%0A });%0A }%0A return { returnValue, stdout, stderr, outputs: populatedOutputs };%0A}%0Avar runPipelineEmscripten_default = runPipelineEmscripten;%0A%0A// dist/core/web-workers/load-image-io-pipeline-module.js%0Avar __await = function(v) {%0A return this instanceof __await ? (this.v = v, this) : new __await(v);%0A};%0Avar __asyncGenerator = function(thisArg, _arguments, generator) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var g = generator.apply(thisArg, _arguments || []), i, q = [];%0A return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i;%0A function verb(n) {%0A if (g[n])%0A i[n] = function(v) {%0A return new Promise(function(a, b) {%0A q.push([n, v, a, b]) > 1 || resume(n, v);%0A });%0A };%0A }%0A function resume(n, v) {%0A try {%0A step(g[n](v));%0A } catch (e) {%0A settle2(q[0][3], e);%0A }%0A }%0A function step(r) {%0A r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle2(q[0][2], r);%0A }%0A function fulfill(value) {%0A resume("next", value);%0A }%0A function reject(value) {%0A resume("throw", value);%0A }%0A function settle2(f, v) {%0A if (f(v), q.shift(), q.length)%0A resume(q[0][0], q[0][1]);%0A }%0A};%0Avar __asyncValues = function(o) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var m = o[Symbol.asyncIterator], i;%0A return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i);%0A function verb(n) {%0A i[n] = o[n] && function(v) {%0A return new Promise(function(resolve, reject) {%0A v = o[n](v), settle2(resolve, reject, v.done, v.value);%0A });%0A };%0A }%0A function settle2(resolve, reject, d, v) {%0A Promise.resolve(v).then(function(v2) {%0A resolve({ value: v2, done: d });%0A }, reject);%0A }%0A};%0Afunction availableIOModules(input) {%0A return __asyncGenerator(this, arguments, function* availableIOModules_1() {%0A for (let idx = 0; idx < ImageIOIndex_default.length; idx++) {%0A const trialIO = ImageIOIndex_default[idx] + "-read-image";%0A const ioModule = yield __await(load_pipeline_module_default(trialIO, input.config.imageIOUrl));%0A yield yield __await(ioModule);%0A }%0A });%0A}%0Aasync function loadImageIOPipelineModule(input, postfix) {%0A var e_1, _a;%0A if (input.mimeType && MimeToImageIO_default.has(input.mimeType)) {%0A const io = MimeToImageIO_default.get(input.mimeType) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.imageIOUrl);%0A return ioModule;%0A }%0A const extension = getFileExtension_default(input.fileName);%0A if (extensionToImageIO_default.has(extension)) {%0A const io = extensionToImageIO_default.get(extension) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.imageIOUrl);%0A return ioModule;%0A }%0A for (let idx = 0; idx < ImageIOIndex_default.length; ++idx) {%0A let idx2 = 0;%0A try {%0A for (var _b = (e_1 = void 0, __asyncValues(availableIOModules(input))), _c; _c = await _b.next(), !_c.done; ) {%0A const pipelineModule = _c.value;%0A try {%0A const { returnValue, outputs } = await runPipelineEmscripten_default(pipelineModule, input.args, input.outputs, input.inputs);%0A if (returnValue === 0) {%0A return pipelineModule;%0A }%0A } catch (error) {%0A }%0A idx2++;%0A }%0A } catch (e_1_1) {%0A e_1 = { error: e_1_1 };%0A } finally {%0A try {%0A if (_c && !_c.done && (_a = _b.return))%0A await _a.call(_b);%0A } finally {%0A if (e_1)%0A throw e_1.error;%0A }%0A }%0A }%0A throw Error(`Could not find IO for: ${input.fileName}`);%0A}%0Avar load_image_io_pipeline_module_default = loadImageIOPipelineModule;%0A%0A// dist/io/internal/MimeToMeshIO.js%0Avar mimeToIO2 = /* @__PURE__ */ new Map([]);%0Avar MimeToMeshIO_default = mimeToIO2;%0A%0A// dist/io/extensionToMeshIO.js%0Avar extensionToIO2 = /* @__PURE__ */ new Map([%0A ["vtk", "VTKPolyDataMeshIO"],%0A ["VTK", "VTKPolyDataMeshIO"],%0A ["byu", "BYUMeshIO"],%0A ["BYU", "BYUMeshIO"],%0A ["fsa", "FreeSurferAsciiMeshIO"],%0A ["FSA", "FreeSurferAsciiMeshIO"],%0A ["fsb", "FreeSurferBinaryMeshIO"],%0A ["FSB", "FreeSurferBinaryMeshIO"],%0A ["obj", "OBJMeshIO"],%0A ["OBJ", "OBJMeshIO"],%0A ["off", "OFFMeshIO"],%0A ["OFF", "OFFMeshIO"],%0A ["stl", "STLMeshIO"],%0A ["STL", "STLMeshIO"],%0A ["swc", "SWCMeshIO"],%0A ["SWC", "SWCMeshIO"],%0A ["iwm", "WasmMeshIO"],%0A ["iwm.cbor", "WasmMeshIO"],%0A ["iwm.cbor.zst", "WasmZstdMeshIO"]%0A]);%0Avar extensionToMeshIO_default = extensionToIO2;%0A%0A// dist/io/internal/MeshIOIndex.js%0Avar MeshIOIndex = ["BYUMeshIO", "FreeSurferAsciiMeshIO", "FreeSurferBinaryMeshIO", "OBJMeshIO", "OFFMeshIO", "STLMeshIO", "SWCMeshIO", "VTKPolyDataMeshIO", "WasmMeshIO", "WasmZstdMeshIO"];%0Avar MeshIOIndex_default = MeshIOIndex;%0A%0A// dist/core/web-workers/load-mesh-io-pipeline-module.js%0Avar __await2 = function(v) {%0A return this instanceof __await2 ? (this.v = v, this) : new __await2(v);%0A};%0Avar __asyncGenerator2 = function(thisArg, _arguments, generator) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var g = generator.apply(thisArg, _arguments || []), i, q = [];%0A return i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i;%0A function verb(n) {%0A if (g[n])%0A i[n] = function(v) {%0A return new Promise(function(a, b) {%0A q.push([n, v, a, b]) > 1 || resume(n, v);%0A });%0A };%0A }%0A function resume(n, v) {%0A try {%0A step(g[n](v));%0A } catch (e) {%0A settle2(q[0][3], e);%0A }%0A }%0A function step(r) {%0A r.value instanceof __await2 ? Promise.resolve(r.value.v).then(fulfill, reject) : settle2(q[0][2], r);%0A }%0A function fulfill(value) {%0A resume("next", value);%0A }%0A function reject(value) {%0A resume("throw", value);%0A }%0A function settle2(f, v) {%0A if (f(v), q.shift(), q.length)%0A resume(q[0][0], q[0][1]);%0A }%0A};%0Avar __asyncValues2 = function(o) {%0A if (!Symbol.asyncIterator)%0A throw new TypeError("Symbol.asyncIterator is not defined.");%0A var m = o[Symbol.asyncIterator], i;%0A return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function() {%0A return this;%0A }, i);%0A function verb(n) {%0A i[n] = o[n] && function(v) {%0A return new Promise(function(resolve, reject) {%0A v = o[n](v), settle2(resolve, reject, v.done, v.value);%0A });%0A };%0A }%0A function settle2(resolve, reject, d, v) {%0A Promise.resolve(v).then(function(v2) {%0A resolve({ value: v2, done: d });%0A }, reject);%0A }%0A};%0Afunction availableIOModules2(input) {%0A return __asyncGenerator2(this, arguments, function* availableIOModules_1() {%0A for (let idx = 0; idx < MeshIOIndex_default.length; idx++) {%0A const trialIO = MeshIOIndex_default[idx] + "-read-mesh";%0A const ioModule = yield __await2(load_pipeline_module_default(trialIO, input.config.meshIOUrl));%0A yield yield __await2(ioModule);%0A }%0A });%0A}%0Aasync function loadMeshIOPipelineModule(input, postfix) {%0A var e_1, _a;%0A if (input.mimeType && MimeToMeshIO_default.has(input.mimeType)) {%0A const io = MimeToMeshIO_default.get(input.mimeType) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.meshIOUrl);%0A return ioModule;%0A }%0A const extension = getFileExtension_default(input.fileName);%0A if (extensionToMeshIO_default.has(extension)) {%0A const io = extensionToMeshIO_default.get(extension) + postfix;%0A const ioModule = await load_pipeline_module_default(io, input.config.meshIOUrl);%0A return ioModule;%0A }%0A for (let idx = 0; idx < MeshIOIndex_default.length; ++idx) {%0A let idx2 = 0;%0A try {%0A for (var _b = (e_1 = void 0, __asyncValues2(availableIOModules2(input))), _c; _c = await _b.next(), !_c.done; ) {%0A const pipelineModule = _c.value;%0A try {%0A const { returnValue, outputs } = await runPipelineEmscripten_default(pipelineModule, input.args, input.outputs, input.inputs);%0A if (returnValue === 0) {%0A return pipelineModule;%0A }%0A } catch (error) {%0A }%0A idx2++;%0A }%0A } catch (e_1_1) {%0A e_1 = { error: e_1_1 };%0A } finally {%0A try {%0A if (_c && !_c.done && (_a = _b.return))%0A await _a.call(_b);%0A } finally {%0A if (e_1)%0A throw e_1.error;%0A }%0A }%0A }%0A throw Error(`Could not find IO for: ${input.fileName}`);%0A}%0Avar load_mesh_io_pipeline_module_default = loadMeshIOPipelineModule;%0A%0A// dist/core/web-workers/run-pipeline.js%0Avar import_register = __toESM(require_register(), 1);%0A%0A// dist/core/getTransferables.js%0Avar haveSharedArrayBuffer2 = typeof globalThis.SharedArrayBuffer !== "undefined";%0Afunction getTransferables(data) {%0A if (data === void 0 || data === null) {%0A return [];%0A }%0A const transferables = [];%0A for (let i = 0; i < data.length; i++) {%0A const transferable = getTransferable(data[i]);%0A if (transferable !== null) {%0A transferables.push(transferable);%0A }%0A }%0A return transferables;%0A}%0Afunction getTransferable(data) {%0A if (data === void 0 || data === null) {%0A return null;%0A }%0A let result = null;%0A if (data.buffer !== void 0) {%0A result = data.buffer;%0A } else if (data.byteLength !== void 0) {%0A result = data;%0A }%0A if (haveSharedArrayBuffer2 && result instanceof SharedArrayBuffer) {%0A return null;%0A }%0A return result;%0A}%0Avar getTransferables_default = getTransferables;%0A%0A// dist/core/internal/imageTransferables.js%0Afunction imageTransferables(image) {%0A return [%0A image.data,%0A image.direction%0A ];%0A}%0Avar imageTransferables_default = imageTransferables;%0A%0A// dist/core/internal/meshTransferables.js%0Afunction meshTransferables(mesh) {%0A return [%0A mesh.points,%0A mesh.pointData,%0A mesh.cells,%0A mesh.cellData%0A ];%0A}%0Avar meshTransferables_default = meshTransferables;%0A%0A// dist/core/internal/polyDataTransferables.js%0Afunction polyDataTransferables(polyData) {%0A return [%0A polyData.points,%0A polyData.vertices,%0A polyData.lines,%0A polyData.polygons,%0A polyData.triangleStrips,%0A polyData.pointData,%0A polyData.cellData%0A ];%0A}%0Avar polyDataTransferables_default = polyDataTransferables;%0A%0A// dist/core/web-workers/run-pipeline.js%0Aasync function runPipeline(pipelineModule, args, outputs, inputs) {%0A const result = runPipelineEmscripten_default(pipelineModule, args, outputs, inputs);%0A const transferables = [];%0A if (result.outputs) {%0A result.outputs.forEach(function(output) {%0A if (output.type === InterfaceTypes_default.BinaryStream || output.type === InterfaceTypes_default.BinaryFile) {%0A const binary = output.data;%0A transferables.push(binary);%0A } else if (output.type === InterfaceTypes_default.Image) {%0A const image = output.data;%0A transferables.push(...imageTransferables_default(image));%0A } else if (output.type === InterfaceTypes_default.Mesh) {%0A const mesh = output.data;%0A transferables.push(...meshTransferables_default(mesh));%0A } else if (output.type === InterfaceTypes_default.PolyData) {%0A const polyData = output.data;%0A transferables.push(...polyDataTransferables_default(polyData));%0A } else if (output.type === IOTypes_default.Binary) {%0A const binary = output.data;%0A transferables.push(binary);%0A } else if (output.type === IOTypes_default.Image) {%0A const image = output.data;%0A transferables.push(...imageTransferables_default(image));%0A } else if (output.type === IOTypes_default.Mesh) {%0A const mesh = output.data;%0A transferables.push(...meshTransferables_default(mesh));%0A }%0A });%0A }%0A return new import_register.default.TransferableResponse(result, getTransferables_default(transferables));%0A}%0Avar run_pipeline_default = runPipeline;%0A%0A// dist/core/web-workers/itk-wasm-pipeline.worker.js%0A(0, import_register2.default)(async function(input) {%0A let pipelineModule = null;%0A if (input.operation === "runPipeline") {%0A const pipelineBaseUrl = typeof input.config[input.pipelineBaseUrl] === "undefined" ? input.pipelineBaseUrl : input.config[input.pipelineBaseUrl];%0A pipelineModule = await load_pipeline_module_default(input.pipelinePath, pipelineBaseUrl);%0A } else if (input.operation === "readImage") {%0A pipelineModule = await load_image_io_pipeline_module_default(input, "-read-image");%0A } else if (input.operation === "writeImage") {%0A pipelineModule = await load_image_io_pipeline_module_default(input, "-write-image");%0A } else if (input.operation === "readMesh") {%0A pipelineModule = await load_mesh_io_pipeline_module_default(input, "-read-mesh");%0A } else if (input.operation === "writeMesh") {%0A pipelineModule = await load_mesh_io_pipeline_module_default(input, "-write-mesh");%0A } else if (input.operation === "meshToPolyData") {%0A pipelineModule = await load_pipeline_module_default("mesh-to-polydata", input.config.meshIOUrl);%0A } else if (input.operation === "polyDataToMesh") {%0A pipelineModule = await load_pipeline_module_default("polydata-to-mesh", input.config.meshIOUrl);%0A } else if (input.operation === "readDICOMImageSeries") {%0A pipelineModule = await load_pipeline_module_default("read-image-dicom-file-series", input.config.imageIOUrl);%0A } else if (input.operation === "readDICOMTags") {%0A pipelineModule = await load_pipeline_module_default("read-dicom-tags", input.config.imageIOUrl);%0A } else {%0A throw new Error("Unknown worker operation");%0A }%0A return run_pipeline_default(pipelineModule, input.args, input.outputs, input.inputs);%0A});%0A'; - -// src/index-worker-embedded.ts -setPipelineWorkerUrl(itk_wasm_pipeline_worker_default); -export { - bio_rad_read_image_default as bioRadReadImage, - bio_rad_write_image_default as bioRadWriteImage, - bmp_read_image_default as bmpReadImage, - bmp_write_image_default as bmpWriteImage, - fdf_read_image_default as fdfReadImage, - fdf_write_image_default as fdfWriteImage, - gdcm_read_image_default as gdcmReadImage, - gdcm_write_image_default as gdcmWriteImage, - ge4_read_image_default as ge4ReadImage, - ge4_write_image_default as ge4WriteImage, - ge5_read_image_default as ge5ReadImage, - ge5_write_image_default as ge5WriteImage, - ge_adw_read_image_default as geAdwReadImage, - ge_adw_write_image_default as geAdwWriteImage, - getPipelineWorkerUrl2 as getPipelineWorkerUrl, - getPipelinesBaseUrl2 as getPipelinesBaseUrl, - gipl_read_image_default as giplReadImage, - gipl_write_image_default as giplWriteImage, - hdf5_read_image_default as hdf5ReadImage, - hdf5_write_image_default as hdf5WriteImage, - jpeg_read_image_default as jpegReadImage, - jpeg_write_image_default as jpegWriteImage, - lsm_read_image_default as lsmReadImage, - lsm_write_image_default as lsmWriteImage, - meta_read_image_default as metaReadImage, - meta_write_image_default as metaWriteImage, - mgh_read_image_default as mghReadImage, - mgh_write_image_default as mghWriteImage, - minc_read_image_default as mincReadImage, - minc_write_image_default as mincWriteImage, - mrc_read_image_default as mrcReadImage, - mrc_write_image_default as mrcWriteImage, - nifti_read_image_default as niftiReadImage, - nifti_write_image_default as niftiWriteImage, - nrrd_read_image_default as nrrdReadImage, - nrrd_write_image_default as nrrdWriteImage, - png_read_image_default as pngReadImage, - png_write_image_default as pngWriteImage, - read_image_default as readImage, - read_image_file_series_default as readImageFileSeries, - scanco_read_image_default as scancoReadImage, - scanco_write_image_default as scancoWriteImage, - setPipelineWorkerUrl, - setPipelinesBaseUrl, - tiff_read_image_default as tiffReadImage, - tiff_write_image_default as tiffWriteImage, - vtk_read_image_default as vtkReadImage, - vtk_write_image_default as vtkWriteImage, - wasm_read_image_default as wasmReadImage, - wasm_write_image_default as wasmWriteImage, - wasm_zstd_read_image_default as wasmZstdReadImage, - wasm_zstd_write_image_default as wasmZstdWriteImage, - write_image_default as writeImage -}; -""" +default_js_module = """data:text/javascript;base64,dmFyIGZyPSIxLjAuMC1iLjE1NCIscmU9ZnI7dmFyIGNyPXtwaXBlbGluZVdvcmtlclVybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstd2FzbUAke3JlfS9kaXN0L2NvcmUvd2ViLXdvcmtlcnMvYnVuZGxlcy9waXBlbGluZS5taW4ud29ya2VyLmpzYCxpbWFnZUlPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1pbWFnZS1pb0Ake3JlfWAsbWVzaElPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1tZXNoLWlvQCR7cmV9YCxwaXBlbGluZXNVcmw6YGh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vaXRrLXdhc21AJHtyZX0vZGlzdC9waXBlbGluZXNgfSx2PWNyO3ZhciBkcj17VGV4dEZpbGU6IkludGVyZmFjZVRleHRGaWxlIixCaW5hcnlGaWxlOiJJbnRlcmZhY2VCaW5hcnlGaWxlIixUZXh0U3RyZWFtOiJJbnRlcmZhY2VUZXh0U3RyZWFtIixCaW5hcnlTdHJlYW06IkludGVyZmFjZUJpbmFyeVN0cmVhbSIsSW1hZ2U6IkludGVyZmFjZUltYWdlIixNZXNoOiJJbnRlcmZhY2VNZXNoIixQb2x5RGF0YToiSW50ZXJmYWNlUG9seURhdGEiLEpzb25Db21wYXRpYmxlOiJJbnRlcmZhY2VKc29uQ29tcGF0aWJsZSJ9LG09ZHI7dmFyIEJyPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0sUT1Ccjt2YXIgQ3I9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFM9Q3I7dmFyIHlyPXtUZXh0OiJUZXh0IixCaW5hcnk6IkJpbmFyeSIsSW1hZ2U6IkltYWdlIixNZXNoOiJNZXNoIn0sVz15cjt2YXIgRXI9e1Vua25vd246IlVua25vd24iLFNjYWxhcjoiU2NhbGFyIixSR0I6IlJHQiIsUkdCQToiUkdCQSIsT2Zmc2V0OiJPZmZzZXQiLFZlY3RvcjoiVmVjdG9yIixQb2ludDoiUG9pbnQiLENvdmFyaWFudFZlY3RvcjoiQ292YXJpYW50VmVjdG9yIixTeW1tZXRyaWNTZWNvbmRSYW5rVGVuc29yOiJTeW1tZXRyaWNTZWNvbmRSYW5rVGVuc29yIixEaWZmdXNpb25UZW5zb3IzRDoiRGlmZnVzaW9uVGVuc29yM0QiLENvbXBsZXg6IkNvbXBsZXgiLEZpeGVkQXJyYXk6IkZpeGVkQXJyYXkiLEFycmF5OiJBcnJheSIsTWF0cml4OiJNYXRyaXgiLFZhcmlhYmxlTGVuZ3RoVmVjdG9yOiJWYXJpYWJsZUxlbmd0aFZlY3RvciIsVmFyaWFibGVTaXplTWF0cml4OiJWYXJpYWJsZVNpemVNYXRyaXgifSx1ZT1FcjtmdW5jdGlvbiBRcihlLEEsdCxyLGEpe2Vbcit0KkFdPWF9dmFyIHN0PVFyO3ZhciBOZT1jbGFzc3tjb25zdHJ1Y3RvcihBPTIsdD1RLlVJbnQ4LHI9dWUuU2NhbGFyLGE9MSl7dGhpcy5kaW1lbnNpb249QSx0aGlzLmNvbXBvbmVudFR5cGU9dCx0aGlzLnBpeGVsVHlwZT1yLHRoaXMuY29tcG9uZW50cz1hfX0sSXQ9TmU7dmFyIFBlPWNsYXNze2NvbnN0cnVjdG9yKEE9bmV3IEl0KXt0aGlzLmltYWdlVHlwZT1BLHRoaXMubmFtZT0iaW1hZ2UiO2xldCB0PUEuZGltZW5zaW9uO3RoaXMub3JpZ2luPW5ldyBBcnJheSh0KSx0aGlzLm9yaWdpbi5maWxsKDApLHRoaXMuc3BhY2luZz1uZXcgQXJyYXkodCksdGhpcy5zcGFjaW5nLmZpbGwoMSksdGhpcy5kaXJlY3Rpb249bmV3IEZsb2F0NjRBcnJheSh0KnQpLHRoaXMuZGlyZWN0aW9uLmZpbGwoMCk7Zm9yKGxldCByPTA7cjx0O3IrKylzdCh0aGlzLmRpcmVjdGlvbix0LHIsciwxKTt0aGlzLnNpemU9bmV3IEFycmF5KHQpLHRoaXMuc2l6ZS5maWxsKDApLHRoaXMubWV0YWRhdGE9bmV3IE1hcCx0aGlzLmRhdGE9bnVsbH19LEs9UGU7ZnVuY3Rpb24gaHIoZSxBKXtsZXQgdD1udWxsO3N3aXRjaChlKXtjYXNlIFEuVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDg6e3Q9bmV3IEludDhBcnJheShBKTticmVha31jYXNlIFEuVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShBKTticmVha31jYXNlIFEuSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KEEpO2JyZWFrfWNhc2UgUS5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KEEpOnQ9bmV3IFVpbnQ4QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoQSk6dD1uZXcgVWludDhBcnJheShBKTticmVha31jYXNlIFMuRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KEEpO2JyZWFrfWNhc2UgUy5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoQSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIEQ9aHI7ZnVuY3Rpb24gd3IoZSl7bGV0IEE9bmV3IEsoZS5pbWFnZVR5cGUpO2lmKEEubmFtZT1lLm5hbWUsQS5vcmlnaW49QXJyYXkuZnJvbShlLm9yaWdpbiksQS5zcGFjaW5nPUFycmF5LmZyb20oZS5zcGFjaW5nKSxBLmRpcmVjdGlvbj1lLmRpcmVjdGlvbi5zbGljZSgpLEEuc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSksZS5kYXRhIT09bnVsbCl7bGV0IHQ9ZS5kYXRhLmNvbnN0cnVjdG9yO0EuZGF0YT1uZXcgdChlLmRhdGEubGVuZ3RoKSxBLmRhdGEhPW51bGwmJkEuZGF0YS5zZXQoZS5kYXRhLDApfXJldHVybiBBfXZhciB4ZT13cjtmdW5jdGlvbiBScihlKXtpZihlLmxlbmd0aDwxKXRocm93IEVycm9yKCJBdCBsZWFzdCBvbmUgaW1hZ2VzIGlzIHJlcXVpcmVkLiIpO2xldCBBPWVbMF07aWYoQS5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiSW1hZ2UgZGF0YSBpcyBudWxsLiIpO2xldCB0PW5ldyBLKEEuaW1hZ2VUeXBlKTt0Lm9yaWdpbj1BcnJheS5mcm9tKEEub3JpZ2luKSx0LnNwYWNpbmc9QXJyYXkuZnJvbShBLnNwYWNpbmcpO2xldCByPXQuaW1hZ2VUeXBlLmRpbWVuc2lvbjt0LmRpcmVjdGlvbj1BLmRpcmVjdGlvbi5zbGljZSgpO2xldCBhPXItMTt0LnNpemU9QXJyYXkuZnJvbShBLnNpemUpO2xldCBvPWUucmVkdWNlKChuLHUpPT5uK3Uuc2l6ZVthXSwwKTt0LnNpemVbYV09bztsZXQgaT10LnNpemUucmVkdWNlKChuLHUpPT5uKnUsMSkqdC5pbWFnZVR5cGUuY29tcG9uZW50cyxsPUEuZGF0YS5jb25zdHJ1Y3Rvcjt0LmRhdGE9bmV3IGwoaSk7bGV0IGY9dC5pbWFnZVR5cGUuY29tcG9uZW50cztmb3IobGV0IG49MDtuPHQuc2l6ZS5sZW5ndGgtMTtuKyspZio9dC5zaXplW25dO2xldCBnPTA7aWYodC5kYXRhIT1udWxsKWZvcihsZXQgbj0wO248ZS5sZW5ndGg7bisrKXQuZGF0YS5zZXQoZVtuXS5kYXRhLGYqZyksZys9ZVtuXS5zaXplW2FdO2Vsc2UgdGhyb3cgRXJyb3IoIkNvdWxkIG5vdCBjcmVhdGUgcmVzdWx0IGltYWdlIGRhdGEuIik7cmV0dXJuIHR9dmFyIEdlPVJyO2Z1bmN0aW9uIGJyKGUsQSl7bGV0IHQ9T2JqZWN0LmFzc2lnbih7fSxlLmltYWdlVHlwZSk7aWYodHlwZW9mIEE8InUiJiZ0eXBlb2YgQS5waXhlbFR5cGU8InUiJiYodC5waXhlbFR5cGU9QS5waXhlbFR5cGUsQS5waXhlbFR5cGU9PT11ZS5TY2FsYXImJnQuY29tcG9uZW50cyE9PTEpKXRocm93IG5ldyBFcnJvcigiQ2Fubm90IGNhc3QgbXVsdGktY29tcG9uZW50IGltYWdlIHRvIGEgc2NhbGFyIGltYWdlIik7dHlwZW9mIEE8InUiJiZ0eXBlb2YgQS5jb21wb25lbnRUeXBlPCJ1IiYmQS5jb21wb25lbnRUeXBlIT09ZS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSYmKHQuY29tcG9uZW50VHlwZT1BLmNvbXBvbmVudFR5cGUpO2xldCByPW5ldyBLKHQpO2lmKHIubmFtZT1lLm5hbWUsci5vcmlnaW49QXJyYXkuZnJvbShlLm9yaWdpbiksci5zcGFjaW5nPUFycmF5LmZyb20oZS5zcGFjaW5nKSxyLmRpcmVjdGlvbj1lLmRpcmVjdGlvbi5zbGljZSgpLHIuc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSksci5tZXRhZGF0YT1uZXcgTWFwKEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShlLm1ldGFkYXRhKSkpKSxlLmRhdGEhPT1udWxsKWlmKHR5cGVvZiBBPCJ1IiYmdHlwZW9mIEEuY29tcG9uZW50VHlwZTwidSImJkEuY29tcG9uZW50VHlwZSE9PWUuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpc3dpdGNoKGUuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpe2Nhc2UgUS5VSW50ODpjYXNlIFEuSW50ODpjYXNlIFEuVUludDE2OmNhc2UgUS5JbnQxNjpjYXNlIFEuVUludDMyOmNhc2UgUS5JbnQzMjpjYXNlIFMuRmxvYXQzMjpjYXNlIFMuRmxvYXQ2NDpzd2l0Y2goci5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSl7Y2FzZSBRLlVJbnQ4OnIuZGF0YT1uZXcgVWludDhBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQ4OnIuZGF0YT1uZXcgSW50OEFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQxNjpyLmRhdGE9bmV3IFVpbnQxNkFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLkludDE2OnIuZGF0YT1uZXcgSW50MTZBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5VSW50MzI6ci5kYXRhPW5ldyBVaW50MzJBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQzMjpyLmRhdGE9bmV3IEludDMyQXJyYXkoZS5kYXRhKTticmVhaztjYXNlIFMuRmxvYXQzMjpyLmRhdGE9bmV3IEZsb2F0MzJBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUy5GbG9hdDY0OnIuZGF0YT1uZXcgRmxvYXQ2NEFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQ2NDpyLmRhdGE9bmV3IEJpZ1VpbnQ2NEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPUJpZ0ludC5hc0ludE4oNjQsQmlnSW50KGUuZGF0YVthXSkpO2JyZWFrO2Nhc2UgUS5JbnQ2NDpyLmRhdGE9bmV3IEJpZ0ludDY0QXJyYXkoZS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBhPTA7YTxyLmRhdGEubGVuZ3RoO2ErKylyLmRhdGFbYV09QmlnSW50LmFzVWludE4oNjQsQmlnSW50KGUuZGF0YVthXSkpO2JyZWFrfWJyZWFrO2Nhc2UgUS5VSW50NjQ6Y2FzZSBRLkludDY0OnN3aXRjaChyLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKXtjYXNlIFEuVUludDg6ci5kYXRhPW5ldyBVaW50OEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5JbnQ4OnIuZGF0YT1uZXcgSW50OEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50MTY6ci5kYXRhPW5ldyBVaW50MTZBcnJheShlLmRhdGEubGVuZ3RoKTtmb3IobGV0IGE9MDthPHIuZGF0YS5sZW5ndGg7YSsrKXIuZGF0YVthXT1OdW1iZXIoZS5kYXRhW2FdKTticmVhaztjYXNlIFEuSW50MTY6ci5kYXRhPW5ldyBJbnQxNkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50MzI6ci5kYXRhPW5ldyBVaW50MzJBcnJheShlLmRhdGEubGVuZ3RoKTtmb3IobGV0IGE9MDthPHIuZGF0YS5sZW5ndGg7YSsrKXIuZGF0YVthXT1OdW1iZXIoZS5kYXRhW2FdKTticmVhaztjYXNlIFEuSW50MzI6ci5kYXRhPW5ldyBJbnQzMkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUy5GbG9hdDMyOnIuZGF0YT1uZXcgRmxvYXQzMkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUy5GbG9hdDY0OnIuZGF0YT1uZXcgRmxvYXQ2NEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50NjQ6ci5kYXRhPW5ldyBCaWdVaW50NjRBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQ2NDpyLmRhdGE9bmV3IEJpZ0ludDY0QXJyYXkoZS5kYXRhKTticmVha31icmVha31lbHNle2xldCBhPWUuZGF0YS5jb25zdHJ1Y3RvcjtyLmRhdGE9bmV3IGEoZS5kYXRhLmxlbmd0aCksci5kYXRhIT1udWxsJiZyLmRhdGEuc2V0KGUuZGF0YSwwKX1yZXR1cm4gcn12YXIgVD1icjt2YXIga3I9ZnVuY3Rpb24oZSxBKXt2YXIgdD17fTtmb3IodmFyIHIgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmQS5pbmRleE9mKHIpPDAmJih0W3JdPWVbcl0pO2lmKGUhPW51bGwmJnR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzPT0iZnVuY3Rpb24iKWZvcih2YXIgYT0wLHI9T2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhlKTthPHIubGVuZ3RoO2ErKylBLmluZGV4T2YoclthXSk8MCYmT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKGUsclthXSkmJih0W3JbYV1dPWVbclthXV0pO3JldHVybiB0fSxUZT1jbGFzc3tjb25zdHJ1Y3RvcihBLHQpe3RoaXMuZmNuPXQsdGhpcy53b3JrZXJRdWV1ZT1uZXcgQXJyYXkoQSksdGhpcy53b3JrZXJRdWV1ZS5maWxsKG51bGwpLHRoaXMucnVuSW5mbz1bXX1ydW5UYXNrcyhBLHQ9bnVsbCl7bGV0IHI9e3Rhc2tRdWV1ZTpbXSxyZXN1bHRzOltdLGFkZGluZ1Rhc2tzOiExLHBvc3Rwb25lZDohMSxydW5uaW5nV29ya2VyczowLGluZGV4OjAsY29tcGxldGVkVGFza3M6MCxwcm9ncmVzc0NhbGxiYWNrOnQsY2FuY2VsZWQ6ITF9O3JldHVybiB0aGlzLnJ1bkluZm8ucHVzaChyKSxyLmluZGV4PXRoaXMucnVuSW5mby5sZW5ndGgtMSx7cHJvbWlzZTpuZXcgUHJvbWlzZSgoYSxvKT0+e3IucmVzb2x2ZT1hLHIucmVqZWN0PW8sci5yZXN1bHRzPW5ldyBBcnJheShBLmxlbmd0aCksci5jb21wbGV0ZWRUYXNrcz0wLHIuYWRkaW5nVGFza3M9ITAsQS5mb3JFYWNoKChpLGwpPT57dGhpcy5hZGRUYXNrKHIuaW5kZXgsbCxpKX0pLHIuYWRkaW5nVGFza3M9ITF9KSxydW5JZDpyLmluZGV4fX10ZXJtaW5hdGVXb3JrZXJzKCl7Zm9yKGxldCBBPTA7QTx0aGlzLndvcmtlclF1ZXVlLmxlbmd0aDtBKyspe2xldCB0PXRoaXMud29ya2VyUXVldWVbQV07dD8udGVybWluYXRlKCksdGhpcy53b3JrZXJRdWV1ZVtBXT1udWxsfX1jYW5jZWwoQSl7bGV0IHQ9dGhpcy5ydW5JbmZvW0FdO3QhPW51bGwmJih0LmNhbmNlbGVkPSEwKX1hZGRUYXNrKEEsdCxyKXtsZXQgYT10aGlzLnJ1bkluZm9bQV07aWYoYT8uY2FuY2VsZWQ9PT0hMCl7YS5yZWplY3QoIlJlbWFpbmluZyB0YXNrcyBjYW5jZWxlZCIpLHRoaXMuY2xlYXJUYXNrKGEuaW5kZXgpO3JldHVybn1pZih0aGlzLndvcmtlclF1ZXVlLmxlbmd0aD4wKXtsZXQgbz10aGlzLndvcmtlclF1ZXVlLnBvcCgpO2EucnVubmluZ1dvcmtlcnMrKyx0aGlzLmZjbihvLC4uLnIpLnRoZW4oaT0+e3Zhcnt3ZWJXb3JrZXI6bH09aSxmPWtyKGksWyJ3ZWJXb3JrZXIiXSk7aWYodGhpcy53b3JrZXJRdWV1ZS5wdXNoKGwpLHRoaXMucnVuSW5mb1tBXSE9PW51bGwpe2lmKGEucnVubmluZ1dvcmtlcnMtLSxhLnJlc3VsdHNbdF09ZixhLmNvbXBsZXRlZFRhc2tzKyssYS5wcm9ncmVzc0NhbGxiYWNrIT1udWxsJiZhLnByb2dyZXNzQ2FsbGJhY2soYS5jb21wbGV0ZWRUYXNrcyxhLnJlc3VsdHMubGVuZ3RoKSxhLnRhc2tRdWV1ZS5sZW5ndGg+MCl7bGV0IGc9YS50YXNrUXVldWUuc2hpZnQoKTt0aGlzLmFkZFRhc2soQSxnWzBdLGdbMV0pfWVsc2UgaWYoIWEuYWRkaW5nVGFza3MmJmEucnVubmluZ1dvcmtlcnM9PT0wKXtsZXQgZz1hLnJlc3VsdHM7YS5yZXNvbHZlKGcpLHRoaXMuY2xlYXJUYXNrKGEuaW5kZXgpfX19KS5jYXRjaChpPT57YS5yZWplY3QoaSksdGhpcy5jbGVhclRhc2soYS5pbmRleCl9KX1lbHNlIGEucnVubmluZ1dvcmtlcnMhPT0wfHxhLnBvc3Rwb25lZD9hLnRhc2tRdWV1ZS5wdXNoKFt0LHJdKTooYS5wb3N0cG9uZWQ9ITAsc2V0VGltZW91dCgoKT0+e2EucG9zdHBvbmVkPSExLHRoaXMuYWRkVGFzayhhLmluZGV4LHQscil9LDUwKSl9Y2xlYXJUYXNrKEEpe3RoaXMucnVuSW5mb1tBXS5yZXN1bHRzPVtdLHRoaXMucnVuSW5mb1tBXS50YXNrUXVldWU9W10sdGhpcy5ydW5JbmZvW0FdLnByb2dyZXNzQ2FsbGJhY2s9bnVsbCx0aGlzLnJ1bkluZm9bQV0uY2FuY2VsZWQ9bnVsbCx0aGlzLnJ1bkluZm9bQV0ucmVqZWN0PSgpPT57fSx0aGlzLnJ1bkluZm9bQV0ucmVzb2x2ZT0oKT0+e319fSxKZT1UZTt2YXIgRHI9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIEZyKGUpe2lmKGU9PW51bGwpcmV0dXJuW107bGV0IEE9W107Zm9yKGxldCB0PTA7dDxlLmxlbmd0aDt0Kyspe2xldCByPU9yKGVbdF0pO3IhPT1udWxsJiZBLnB1c2gocil9cmV0dXJuIEF9ZnVuY3Rpb24gT3IoZSl7aWYoZT09bnVsbClyZXR1cm4gbnVsbDtsZXQgQT1udWxsO3JldHVybiBlLmJ1ZmZlciE9PXZvaWQgMD9BPWUuYnVmZmVyOmUuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKEE9ZSksRHImJkEgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOkF9dmFyIGx0PUZyO2Z1bmN0aW9uIGllKGUsQSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUuYXBwbHkoQSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6VXJ9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOkhlfT1PYmplY3QsY2U9KGU9PkE9PntsZXQgdD1Vci5jYWxsKEEpO3JldHVybiBlW3RdfHwoZVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSkseD1lPT4oZT1lLnRvTG93ZXJDYXNlKCksQT0+Y2UoQSk9PT1lKSxkZT1lPT5BPT50eXBlb2YgQT09PWUse2lzQXJyYXk6an09QXJyYXksYWU9ZGUoInVuZGVmaW5lZCIpO2Z1bmN0aW9uIFNyKGUpe3JldHVybiBlIT09bnVsbCYmIWFlKGUpJiZlLmNvbnN0cnVjdG9yIT09bnVsbCYmIWFlKGUuY29uc3RydWN0b3IpJiZQKGUuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZlLmNvbnN0cnVjdG9yLmlzQnVmZmVyKGUpfXZhciBtdD14KCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIFdyKGUpe2xldCBBO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/QT1BcnJheUJ1ZmZlci5pc1ZpZXcoZSk6QT1lJiZlLmJ1ZmZlciYmbXQoZS5idWZmZXIpLEF9dmFyIE5yPWRlKCJzdHJpbmciKSxQPWRlKCJmdW5jdGlvbiIpLHV0PWRlKCJudW1iZXIiKSxCZT1lPT5lIT09bnVsbCYmdHlwZW9mIGU9PSJvYmplY3QiLFByPWU9PmU9PT0hMHx8ZT09PSExLGZlPWU9PntpZihjZShlKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBBPUhlKGUpO3JldHVybihBPT09bnVsbHx8QT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihBKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBlKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gZSl9LHhyPXgoIkRhdGUiKSxHcj14KCJGaWxlIiksVHI9eCgiQmxvYiIpLEpyPXgoIkZpbGVMaXN0IiksTHI9ZT0+QmUoZSkmJlAoZS5waXBlKSxNcj1lPT57bGV0IEE7cmV0dXJuIGUmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJmUgaW5zdGFuY2VvZiBGb3JtRGF0YXx8UChlLmFwcGVuZCkmJigoQT1jZShlKSk9PT0iZm9ybWRhdGEifHxBPT09Im9iamVjdCImJlAoZS50b1N0cmluZykmJmUudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sSHI9eCgiVVJMU2VhcmNoUGFyYW1zIiksWXI9ZT0+ZS50cmltP2UudHJpbSgpOmUucmVwbGFjZSgvXltcc1x1RkVGRlx4QTBdK3xbXHNcdUZFRkZceEEwXSskL2csIiIpO2Z1bmN0aW9uIG9lKGUsQSx7YWxsT3duS2V5czp0PSExfT17fSl7aWYoZT09PW51bGx8fHR5cGVvZiBlPiJ1IilyZXR1cm47bGV0IHIsYTtpZih0eXBlb2YgZSE9Im9iamVjdCImJihlPVtlXSksaihlKSlmb3Iocj0wLGE9ZS5sZW5ndGg7cjxhO3IrKylBLmNhbGwobnVsbCxlW3JdLHIsZSk7ZWxzZXtsZXQgbz10P09iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGUpOk9iamVjdC5rZXlzKGUpLGk9by5sZW5ndGgsbDtmb3Iocj0wO3I8aTtyKyspbD1vW3JdLEEuY2FsbChudWxsLGVbbF0sbCxlKX19ZnVuY3Rpb24gZnQoZSxBKXtBPUEudG9Mb3dlckNhc2UoKTtsZXQgdD1PYmplY3Qua2V5cyhlKSxyPXQubGVuZ3RoLGE7Zm9yKDtyLS0gPjA7KWlmKGE9dFtyXSxBPT09YS50b0xvd2VyQ2FzZSgpKXJldHVybiBhO3JldHVybiBudWxsfXZhciBjdD0oKCk9PnR5cGVvZiBnbG9iYWxUaGlzPCJ1Ij9nbG9iYWxUaGlzOnR5cGVvZiBzZWxmPCJ1Ij9zZWxmOnR5cGVvZiB3aW5kb3c8InUiP3dpbmRvdzpnbG9iYWwpKCksZHQ9ZT0+IWFlKGUpJiZlIT09Y3Q7ZnVuY3Rpb24gTWUoKXtsZXR7Y2FzZWxlc3M6ZX09ZHQodGhpcykmJnRoaXN8fHt9LEE9e30sdD0ocixhKT0+e2xldCBvPWUmJmZ0KEEsYSl8fGE7ZmUoQVtvXSkmJmZlKHIpP0Fbb109TWUoQVtvXSxyKTpmZShyKT9BW29dPU1lKHt9LHIpOmoocik/QVtvXT1yLnNsaWNlKCk6QVtvXT1yfTtmb3IobGV0IHI9MCxhPWFyZ3VtZW50cy5sZW5ndGg7cjxhO3IrKylhcmd1bWVudHNbcl0mJm9lKGFyZ3VtZW50c1tyXSx0KTtyZXR1cm4gQX12YXIgcXI9KGUsQSx0LHthbGxPd25LZXlzOnJ9PXt9KT0+KG9lKEEsKGEsbyk9Pnt0JiZQKGEpP2Vbb109aWUoYSx0KTplW29dPWF9LHthbGxPd25LZXlzOnJ9KSxlKSx2cj1lPT4oZS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihlPWUuc2xpY2UoMSkpLGUpLEtyPShlLEEsdCxyKT0+e2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoQS5wcm90b3R5cGUsciksZS5wcm90b3R5cGUuY29uc3RydWN0b3I9ZSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwic3VwZXIiLHt2YWx1ZTpBLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oZS5wcm90b3R5cGUsdCl9LGpyPShlLEEsdCxyKT0+e2xldCBhLG8saSxsPXt9O2lmKEE9QXx8e30sZT09bnVsbClyZXR1cm4gQTtkb3tmb3IoYT1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhlKSxvPWEubGVuZ3RoO28tLSA+MDspaT1hW29dLCghcnx8cihpLGUsQSkpJiYhbFtpXSYmKEFbaV09ZVtpXSxsW2ldPSEwKTtlPXQhPT0hMSYmSGUoZSl9d2hpbGUoZSYmKCF0fHx0KGUsQSkpJiZlIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIEF9LF9yPShlLEEsdCk9PntlPVN0cmluZyhlKSwodD09PXZvaWQgMHx8dD5lLmxlbmd0aCkmJih0PWUubGVuZ3RoKSx0LT1BLmxlbmd0aDtsZXQgcj1lLmluZGV4T2YoQSx0KTtyZXR1cm4gciE9PS0xJiZyPT09dH0senI9ZT0+e2lmKCFlKXJldHVybiBudWxsO2lmKGooZSkpcmV0dXJuIGU7bGV0IEE9ZS5sZW5ndGg7aWYoIXV0KEEpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShBKTtmb3IoO0EtLSA+MDspdFtBXT1lW0FdO3JldHVybiB0fSxWcj0oZT0+QT0+ZSYmQSBpbnN0YW5jZW9mIGUpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmSGUoVWludDhBcnJheSkpLFpyPShlLEEpPT57bGV0IHI9KGUmJmVbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChlKSxhO2Zvcig7KGE9ci5uZXh0KCkpJiYhYS5kb25lOyl7bGV0IG89YS52YWx1ZTtBLmNhbGwoZSxvWzBdLG9bMV0pfX0sWHI9KGUsQSk9PntsZXQgdCxyPVtdO2Zvcig7KHQ9ZS5leGVjKEEpKSE9PW51bGw7KXIucHVzaCh0KTtyZXR1cm4gcn0sJHI9eCgiSFRNTEZvcm1FbGVtZW50IiksZWk9ZT0+ZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xzXShbYS16XGRdKShcdyopL2csZnVuY3Rpb24odCxyLGEpe3JldHVybiByLnRvVXBwZXJDYXNlKCkrYX0pLGd0PSgoe2hhc093blByb3BlcnR5OmV9KT0+KEEsdCk9PmUuY2FsbChBLHQpKShPYmplY3QucHJvdG90eXBlKSxBaT14KCJSZWdFeHAiKSxCdD0oZSxBKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKGUpLHI9e307b2UodCwoYSxvKT0+e2xldCBpOyhpPUEoYSxvLGUpKSE9PSExJiYocltvXT1pfHxhKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGUscil9LHRpPWU9PntCdChlLChBLHQpPT57aWYoUChlKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKHQpIT09LTEpcmV0dXJuITE7bGV0IHI9ZVt0XTtpZihQKHIpKXtpZihBLmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIEEpe0Eud3JpdGFibGU9ITE7cmV0dXJufUEuc2V0fHwoQS5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgJyIrdCsiJyIpfSl9fSl9LHJpPShlLEEpPT57bGV0IHQ9e30scj1hPT57YS5mb3JFYWNoKG89Pnt0W29dPSEwfSl9O3JldHVybiBqKGUpP3IoZSk6cihTdHJpbmcoZSkuc3BsaXQoQSkpLHR9LGlpPSgpPT57fSxhaT0oZSxBKT0+KGU9K2UsTnVtYmVyLmlzRmluaXRlKGUpP2U6QSksTGU9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6IixwdD0iMDEyMzQ1Njc4OSIsQ3Q9e0RJR0lUOnB0LEFMUEhBOkxlLEFMUEhBX0RJR0lUOkxlK0xlLnRvVXBwZXJDYXNlKCkrcHR9LG9pPShlPTE2LEE9Q3QuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpyfT1BO2Zvcig7ZS0tOyl0Kz1BW01hdGgucmFuZG9tKCkqcnwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gbmkoZSl7cmV0dXJuISEoZSYmUChlLmFwcGVuZCkmJmVbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJmVbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIHNpPWU9PntsZXQgQT1uZXcgQXJyYXkoMTApLHQ9KHIsYSk9PntpZihCZShyKSl7aWYoQS5pbmRleE9mKHIpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gcikpe0FbYV09cjtsZXQgbz1qKHIpP1tdOnt9O3JldHVybiBvZShyLChpLGwpPT57bGV0IGY9dChpLGErMSk7IWFlKGYpJiYob1tsXT1mKX0pLEFbYV09dm9pZCAwLG99fXJldHVybiByfTtyZXR1cm4gdChlLDApfSxJaT14KCJBc3luY0Z1bmN0aW9uIiksbGk9ZT0+ZSYmKEJlKGUpfHxQKGUpKSYmUChlLnRoZW4pJiZQKGUuY2F0Y2gpLGM9e2lzQXJyYXk6aixpc0FycmF5QnVmZmVyOm10LGlzQnVmZmVyOlNyLGlzRm9ybURhdGE6TXIsaXNBcnJheUJ1ZmZlclZpZXc6V3IsaXNTdHJpbmc6TnIsaXNOdW1iZXI6dXQsaXNCb29sZWFuOlByLGlzT2JqZWN0OkJlLGlzUGxhaW5PYmplY3Q6ZmUsaXNVbmRlZmluZWQ6YWUsaXNEYXRlOnhyLGlzRmlsZTpHcixpc0Jsb2I6VHIsaXNSZWdFeHA6QWksaXNGdW5jdGlvbjpQLGlzU3RyZWFtOkxyLGlzVVJMU2VhcmNoUGFyYW1zOkhyLGlzVHlwZWRBcnJheTpWcixpc0ZpbGVMaXN0OkpyLGZvckVhY2g6b2UsbWVyZ2U6TWUsZXh0ZW5kOnFyLHRyaW06WXIsc3RyaXBCT006dnIsaW5oZXJpdHM6S3IsdG9GbGF0T2JqZWN0OmpyLGtpbmRPZjpjZSxraW5kT2ZUZXN0OngsZW5kc1dpdGg6X3IsdG9BcnJheTp6cixmb3JFYWNoRW50cnk6WnIsbWF0Y2hBbGw6WHIsaXNIVE1MRm9ybTokcixoYXNPd25Qcm9wZXJ0eTpndCxoYXNPd25Qcm9wOmd0LHJlZHVjZURlc2NyaXB0b3JzOkJ0LGZyZWV6ZU1ldGhvZHM6dGksdG9PYmplY3RTZXQ6cmksdG9DYW1lbENhc2U6ZWksbm9vcDppaSx0b0Zpbml0ZU51bWJlcjphaSxmaW5kS2V5OmZ0LGdsb2JhbDpjdCxpc0NvbnRleHREZWZpbmVkOmR0LEFMUEhBQkVUOkN0LGdlbmVyYXRlU3RyaW5nOm9pLGlzU3BlY0NvbXBsaWFudEZvcm06bmksdG9KU09OT2JqZWN0OnNpLGlzQXN5bmNGbjpJaSxpc1RoZW5hYmxlOmxpfTtmdW5jdGlvbiBfKGUsQSx0LHIsYSl7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPWUsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixBJiYodGhpcy5jb2RlPUEpLHQmJih0aGlzLmNvbmZpZz10KSxyJiYodGhpcy5yZXF1ZXN0PXIpLGEmJih0aGlzLnJlc3BvbnNlPWEpfWMuaW5oZXJpdHMoXyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOmMudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIHl0PV8ucHJvdG90eXBlLEV0PXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goZT0+e0V0W2VdPXt2YWx1ZTplfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKF8sRXQpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh5dCwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtfLmZyb209KGUsQSx0LHIsYSxvKT0+e2xldCBpPU9iamVjdC5jcmVhdGUoeXQpO3JldHVybiBjLnRvRmxhdE9iamVjdChlLGksZnVuY3Rpb24oZil7cmV0dXJuIGYhPT1FcnJvci5wcm90b3R5cGV9LGw9PmwhPT0iaXNBeGlvc0Vycm9yIiksXy5jYWxsKGksZS5tZXNzYWdlLEEsdCxyLGEpLGkuY2F1c2U9ZSxpLm5hbWU9ZS5uYW1lLG8mJk9iamVjdC5hc3NpZ24oaSxvKSxpfTt2YXIgaD1fO3ZhciBDZT1udWxsO2Z1bmN0aW9uIFllKGUpe3JldHVybiBjLmlzUGxhaW5PYmplY3QoZSl8fGMuaXNBcnJheShlKX1mdW5jdGlvbiBodChlKXtyZXR1cm4gYy5lbmRzV2l0aChlLCJbXSIpP2Uuc2xpY2UoMCwtMik6ZX1mdW5jdGlvbiBRdChlLEEsdCl7cmV0dXJuIGU/ZS5jb25jYXQoQSkubWFwKGZ1bmN0aW9uKGEsbyl7cmV0dXJuIGE9aHQoYSksIXQmJm8/IlsiK2ErIl0iOmF9KS5qb2luKHQ/Ii4iOiIiKTpBfWZ1bmN0aW9uIGdpKGUpe3JldHVybiBjLmlzQXJyYXkoZSkmJiFlLnNvbWUoWWUpfXZhciBwaT1jLnRvRmxhdE9iamVjdChjLHt9LG51bGwsZnVuY3Rpb24oQSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KEEpfSk7ZnVuY3Rpb24gbWkoZSxBLHQpe2lmKCFjLmlzT2JqZWN0KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO0E9QXx8bmV3KENlfHxGb3JtRGF0YSksdD1jLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oZCxFKXtyZXR1cm4hYy5pc1VuZGVmaW5lZChFW2RdKX0pO2xldCByPXQubWV0YVRva2VucyxhPXQudmlzaXRvcnx8bixvPXQuZG90cyxpPXQuaW5kZXhlcyxmPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJmMuaXNTcGVjQ29tcGxpYW50Rm9ybShBKTtpZighYy5pc0Z1bmN0aW9uKGEpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gZyhJKXtpZihJPT09bnVsbClyZXR1cm4iIjtpZihjLmlzRGF0ZShJKSlyZXR1cm4gSS50b0lTT1N0cmluZygpO2lmKCFmJiZjLmlzQmxvYihJKSl0aHJvdyBuZXcgaCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gYy5pc0FycmF5QnVmZmVyKEkpfHxjLmlzVHlwZWRBcnJheShJKT9mJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbSV0pOkJ1ZmZlci5mcm9tKEkpOkl9ZnVuY3Rpb24gbihJLGQsRSl7bGV0IFI9STtpZihJJiYhRSYmdHlwZW9mIEk9PSJvYmplY3QiKXtpZihjLmVuZHNXaXRoKGQsInt9IikpZD1yP2Q6ZC5zbGljZSgwLC0yKSxJPUpTT04uc3RyaW5naWZ5KEkpO2Vsc2UgaWYoYy5pc0FycmF5KEkpJiZnaShJKXx8KGMuaXNGaWxlTGlzdChJKXx8Yy5lbmRzV2l0aChkLCJbXSIpKSYmKFI9Yy50b0FycmF5KEkpKSlyZXR1cm4gZD1odChkKSxSLmZvckVhY2goZnVuY3Rpb24oayxXZSl7IShjLmlzVW5kZWZpbmVkKGspfHxrPT09bnVsbCkmJkEuYXBwZW5kKGk9PT0hMD9RdChbZF0sV2Usbyk6aT09PW51bGw/ZDpkKyJbXSIsZyhrKSl9KSwhMX1yZXR1cm4gWWUoSSk/ITA6KEEuYXBwZW5kKFF0KEUsZCxvKSxnKEkpKSwhMSl9bGV0IHU9W10scD1PYmplY3QuYXNzaWduKHBpLHtkZWZhdWx0VmlzaXRvcjpuLGNvbnZlcnRWYWx1ZTpnLGlzVmlzaXRhYmxlOlllfSk7ZnVuY3Rpb24gcyhJLGQpe2lmKCFjLmlzVW5kZWZpbmVkKEkpKXtpZih1LmluZGV4T2YoSSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrZC5qb2luKCIuIikpO3UucHVzaChJKSxjLmZvckVhY2goSSxmdW5jdGlvbihSLHcpeyghKGMuaXNVbmRlZmluZWQoUil8fFI9PT1udWxsKSYmYS5jYWxsKEEsUixjLmlzU3RyaW5nKHcpP3cudHJpbSgpOncsZCxwKSk9PT0hMCYmcyhSLGQ/ZC5jb25jYXQodyk6W3ddKX0pLHUucG9wKCl9fWlmKCFjLmlzT2JqZWN0KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gcyhlKSxBfXZhciBKPW1pO2Z1bmN0aW9uIHd0KGUpe2xldCBBPXsiISI6IiUyMSIsIiciOiIlMjciLCIoIjoiJTI4IiwiKSI6IiUyOSIsIn4iOiIlN0UiLCIlMjAiOiIrIiwiJTAwIjoiXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KGUpLnJlcGxhY2UoL1shJygpfl18JTIwfCUwMC9nLGZ1bmN0aW9uKHIpe3JldHVybiBBW3JdfSl9ZnVuY3Rpb24gUnQoZSxBKXt0aGlzLl9wYWlycz1bXSxlJiZKKGUsdGhpcyxBKX12YXIgYnQ9UnQucHJvdG90eXBlO2J0LmFwcGVuZD1mdW5jdGlvbihBLHQpe3RoaXMuX3BhaXJzLnB1c2goW0EsdF0pfTtidC50b1N0cmluZz1mdW5jdGlvbihBKXtsZXQgdD1BP2Z1bmN0aW9uKHIpe3JldHVybiBBLmNhbGwodGhpcyxyLHd0KX06d3Q7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihhKXtyZXR1cm4gdChhWzBdKSsiPSIrdChhWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIHllPVJ0O2Z1bmN0aW9uIHVpKGUpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoZSkucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfWZ1bmN0aW9uIG5lKGUsQSx0KXtpZighQSlyZXR1cm4gZTtsZXQgcj10JiZ0LmVuY29kZXx8dWksYT10JiZ0LnNlcmlhbGl6ZSxvO2lmKGE/bz1hKEEsdCk6bz1jLmlzVVJMU2VhcmNoUGFyYW1zKEEpP0EudG9TdHJpbmcoKTpuZXcgeWUoQSx0KS50b1N0cmluZyhyKSxvKXtsZXQgaT1lLmluZGV4T2YoIiMiKTtpIT09LTEmJihlPWUuc2xpY2UoMCxpKSksZSs9KGUuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikrb31yZXR1cm4gZX12YXIgcWU9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZShBLHQscil7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOkEscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpyP3Iuc3luY2hyb25vdXM6ITEscnVuV2hlbjpyP3IucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdChBKXt0aGlzLmhhbmRsZXJzW0FdJiYodGhpcy5oYW5kbGVyc1tBXT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKEEpe2MuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHIpe3IhPT1udWxsJiZBKHIpfSl9fSx2ZT1xZTt2YXIgRWU9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9O3ZhciBrdD10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6eWU7dmFyIER0PXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgRnQ9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgZmk9KCgpPT57bGV0IGU7cmV0dXJuIHR5cGVvZiBuYXZpZ2F0b3I8InUiJiYoKGU9bmF2aWdhdG9yLnByb2R1Y3QpPT09IlJlYWN0TmF0aXZlInx8ZT09PSJOYXRpdmVTY3JpcHQifHxlPT09Ik5TIik/ITE6dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSJ9KSgpLGNpPSgoKT0+dHlwZW9mIFdvcmtlckdsb2JhbFNjb3BlPCJ1IiYmc2VsZiBpbnN0YW5jZW9mIFdvcmtlckdsb2JhbFNjb3BlJiZ0eXBlb2Ygc2VsZi5pbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKSgpLEY9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6a3QsRm9ybURhdGE6RHQsQmxvYjpGdH0saXNTdGFuZGFyZEJyb3dzZXJFbnY6ZmksaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6Y2kscHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O2Z1bmN0aW9uIEtlKGUsQSl7cmV0dXJuIEooZSxuZXcgRi5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKHQscixhLG8pe3JldHVybiBGLmlzTm9kZSYmYy5pc0J1ZmZlcih0KT8odGhpcy5hcHBlbmQocix0LnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOm8uZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sQSkpfWZ1bmN0aW9uIGRpKGUpe3JldHVybiBjLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxlKS5tYXAoQT0+QVswXT09PSJbXSI/IiI6QVsxXXx8QVswXSl9ZnVuY3Rpb24gQmkoZSl7bGV0IEE9e30sdD1PYmplY3Qua2V5cyhlKSxyLGE9dC5sZW5ndGgsbztmb3Iocj0wO3I8YTtyKyspbz10W3JdLEFbb109ZVtvXTtyZXR1cm4gQX1mdW5jdGlvbiBDaShlKXtmdW5jdGlvbiBBKHQscixhLG8pe2xldCBpPXRbbysrXSxsPU51bWJlci5pc0Zpbml0ZSgraSksZj1vPj10Lmxlbmd0aDtyZXR1cm4gaT0haSYmYy5pc0FycmF5KGEpP2EubGVuZ3RoOmksZj8oYy5oYXNPd25Qcm9wKGEsaSk/YVtpXT1bYVtpXSxyXTphW2ldPXIsIWwpOigoIWFbaV18fCFjLmlzT2JqZWN0KGFbaV0pKSYmKGFbaV09W10pLEEodCxyLGFbaV0sbykmJmMuaXNBcnJheShhW2ldKSYmKGFbaV09QmkoYVtpXSkpLCFsKX1pZihjLmlzRm9ybURhdGEoZSkmJmMuaXNGdW5jdGlvbihlLmVudHJpZXMpKXtsZXQgdD17fTtyZXR1cm4gYy5mb3JFYWNoRW50cnkoZSwocixhKT0+e0EoZGkociksYSx0LDApfSksdH1yZXR1cm4gbnVsbH12YXIgUWU9Q2k7ZnVuY3Rpb24geWkoZSxBLHQpe2lmKGMuaXNTdHJpbmcoZSkpdHJ5e3JldHVybihBfHxKU09OLnBhcnNlKShlKSxjLnRyaW0oZSl9Y2F0Y2gocil7aWYoci5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyByfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoZSl9dmFyIGplPXt0cmFuc2l0aW9uYWw6RWUsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihBLHQpe2xldCByPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIsYT1yLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxvPWMuaXNPYmplY3QoQSk7aWYobyYmYy5pc0hUTUxGb3JtKEEpJiYoQT1uZXcgRm9ybURhdGEoQSkpLGMuaXNGb3JtRGF0YShBKSlyZXR1cm4gYSYmYT9KU09OLnN0cmluZ2lmeShRZShBKSk6QTtpZihjLmlzQXJyYXlCdWZmZXIoQSl8fGMuaXNCdWZmZXIoQSl8fGMuaXNTdHJlYW0oQSl8fGMuaXNGaWxlKEEpfHxjLmlzQmxvYihBKSlyZXR1cm4gQTtpZihjLmlzQXJyYXlCdWZmZXJWaWV3KEEpKXJldHVybiBBLmJ1ZmZlcjtpZihjLmlzVVJMU2VhcmNoUGFyYW1zKEEpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLEEudG9TdHJpbmcoKTtsZXQgbDtpZihvKXtpZihyLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiBLZShBLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKGw9Yy5pc0ZpbGVMaXN0KEEpKXx8ci5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBmPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gSihsP3siZmlsZXNbXSI6QX06QSxmJiZuZXcgZix0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIG98fGE/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSx5aShBKSk6QX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihBKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8amUudHJhbnNpdGlvbmFsLHI9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxhPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKEEmJmMuaXNTdHJpbmcoQSkmJihyJiYhdGhpcy5yZXNwb25zZVR5cGV8fGEpKXtsZXQgaT0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZhO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShBKX1jYXRjaChsKXtpZihpKXRocm93IGwubmFtZT09PSJTeW50YXhFcnJvciI/aC5mcm9tKGwsaC5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpsfX1yZXR1cm4gQX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6Ri5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6Ri5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKEEpe3JldHVybiBBPj0yMDAmJkE8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07Yy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLGU9PntqZS5oZWFkZXJzW2VdPXt9fSk7dmFyIHo9amU7dmFyIEVpPWMudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksT3Q9ZT0+e2xldCBBPXt9LHQscixhO3JldHVybiBlJiZlLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihpKXthPWkuaW5kZXhPZigiOiIpLHQ9aS5zdWJzdHJpbmcoMCxhKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPWkuc3Vic3RyaW5nKGErMSkudHJpbSgpLCEoIXR8fEFbdF0mJkVpW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/QVt0XT9BW3RdLnB1c2gocik6QVt0XT1bcl06QVt0XT1BW3RdP0FbdF0rIiwgIityOnIpfSksQX07dmFyIFV0PVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gc2UoZSl7cmV0dXJuIGUmJlN0cmluZyhlKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBoZShlKXtyZXR1cm4gZT09PSExfHxlPT1udWxsP2U6Yy5pc0FycmF5KGUpP2UubWFwKGhlKTpTdHJpbmcoZSl9ZnVuY3Rpb24gUWkoZSl7bGV0IEE9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9dC5leGVjKGUpOylBW3JbMV1dPXJbMl07cmV0dXJuIEF9dmFyIGhpPWU9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoZS50cmltKCkpO2Z1bmN0aW9uIF9lKGUsQSx0LHIsYSl7aWYoYy5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyxBLHQpO2lmKGEmJihBPXQpLCEhYy5pc1N0cmluZyhBKSl7aWYoYy5pc1N0cmluZyhyKSlyZXR1cm4gQS5pbmRleE9mKHIpIT09LTE7aWYoYy5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KEEpfX1mdW5jdGlvbiB3aShlKXtyZXR1cm4gZS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLChBLHQscik9PnQudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBSaShlLEEpe2xldCB0PWMudG9DYW1lbENhc2UoIiAiK0EpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KGUscit0LHt2YWx1ZTpmdW5jdGlvbihhLG8saSl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLEEsYSxvLGkpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBWPWNsYXNze2NvbnN0cnVjdG9yKEEpe0EmJnRoaXMuc2V0KEEpfXNldChBLHQscil7bGV0IGE9dGhpcztmdW5jdGlvbiBvKGwsZixnKXtsZXQgbj1zZShmKTtpZighbil0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IHU9Yy5maW5kS2V5KGEsbik7KCF1fHxhW3VdPT09dm9pZCAwfHxnPT09ITB8fGc9PT12b2lkIDAmJmFbdV0hPT0hMSkmJihhW3V8fGZdPWhlKGwpKX1sZXQgaT0obCxmKT0+Yy5mb3JFYWNoKGwsKGcsbik9Pm8oZyxuLGYpKTtyZXR1cm4gYy5pc1BsYWluT2JqZWN0KEEpfHxBIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9pKEEsdCk6Yy5pc1N0cmluZyhBKSYmKEE9QS50cmltKCkpJiYhaGkoQSk/aShPdChBKSx0KTpBIT1udWxsJiZvKHQsQSxyKSx0aGlzfWdldChBLHQpe2lmKEE9c2UoQSksQSl7bGV0IHI9Yy5maW5kS2V5KHRoaXMsQSk7aWYocil7bGV0IGE9dGhpc1tyXTtpZighdClyZXR1cm4gYTtpZih0PT09ITApcmV0dXJuIFFpKGEpO2lmKGMuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsYSxyKTtpZihjLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMoYSk7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhBLHQpe2lmKEE9c2UoQSksQSl7bGV0IHI9Yy5maW5kS2V5KHRoaXMsQSk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCF0fHxfZSh0aGlzLHRoaXNbcl0scix0KSkpfXJldHVybiExfWRlbGV0ZShBLHQpe2xldCByPXRoaXMsYT0hMTtmdW5jdGlvbiBvKGkpe2lmKGk9c2UoaSksaSl7bGV0IGw9Yy5maW5kS2V5KHIsaSk7bCYmKCF0fHxfZShyLHJbbF0sbCx0KSkmJihkZWxldGUgcltsXSxhPSEwKX19cmV0dXJuIGMuaXNBcnJheShBKT9BLmZvckVhY2gobyk6byhBKSxhfWNsZWFyKEEpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLHI9dC5sZW5ndGgsYT0hMTtmb3IoO3ItLTspe2xldCBvPXRbcl07KCFBfHxfZSh0aGlzLHRoaXNbb10sbyxBLCEwKSkmJihkZWxldGUgdGhpc1tvXSxhPSEwKX1yZXR1cm4gYX1ub3JtYWxpemUoQSl7bGV0IHQ9dGhpcyxyPXt9O3JldHVybiBjLmZvckVhY2godGhpcywoYSxvKT0+e2xldCBpPWMuZmluZEtleShyLG8pO2lmKGkpe3RbaV09aGUoYSksZGVsZXRlIHRbb107cmV0dXJufWxldCBsPUE/d2kobyk6U3RyaW5nKG8pLnRyaW0oKTtsIT09byYmZGVsZXRlIHRbb10sdFtsXT1oZShhKSxyW2xdPSEwfSksdGhpc31jb25jYXQoLi4uQSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uQSl9dG9KU09OKEEpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIGMuZm9yRWFjaCh0aGlzLChyLGEpPT57ciE9bnVsbCYmciE9PSExJiYodFthXT1BJiZjLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbQSx0XSk9PkErIjogIit0KS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShBKXtyZXR1cm4gQSBpbnN0YW5jZW9mIHRoaXM/QTpuZXcgdGhpcyhBKX1zdGF0aWMgY29uY2F0KEEsLi4udCl7bGV0IHI9bmV3IHRoaXMoQSk7cmV0dXJuIHQuZm9yRWFjaChhPT5yLnNldChhKSkscn1zdGF0aWMgYWNjZXNzb3IoQSl7bGV0IHI9KHRoaXNbVXRdPXRoaXNbVXRdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsYT10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBvKGkpe2xldCBsPXNlKGkpO3JbbF18fChSaShhLGkpLHJbbF09ITApfXJldHVybiBjLmlzQXJyYXkoQSk/QS5mb3JFYWNoKG8pOm8oQSksdGhpc319O1YuYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO2MucmVkdWNlRGVzY3JpcHRvcnMoVi5wcm90b3R5cGUsKHt2YWx1ZTplfSxBKT0+e2xldCB0PUFbMF0udG9VcHBlckNhc2UoKStBLnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PmUsc2V0KHIpe3RoaXNbdF09cn19fSk7Yy5mcmVlemVNZXRob2RzKFYpO3ZhciBVPVY7ZnVuY3Rpb24gSWUoZSxBKXtsZXQgdD10aGlzfHx6LHI9QXx8dCxhPVUuZnJvbShyLmhlYWRlcnMpLG89ci5kYXRhO3JldHVybiBjLmZvckVhY2goZSxmdW5jdGlvbihsKXtvPWwuY2FsbCh0LG8sYS5ub3JtYWxpemUoKSxBP0Euc3RhdHVzOnZvaWQgMCl9KSxhLm5vcm1hbGl6ZSgpLG99ZnVuY3Rpb24gbGUoZSl7cmV0dXJuISEoZSYmZS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBTdChlLEEsdCl7aC5jYWxsKHRoaXMsZT8/ImNhbmNlbGVkIixoLkVSUl9DQU5DRUxFRCxBLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9Yy5pbmhlcml0cyhTdCxoLHtfX0NBTkNFTF9fOiEwfSk7dmFyIEw9U3Q7ZnVuY3Rpb24gemUoZSxBLHQpe2xldCByPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IXJ8fHIodC5zdGF0dXMpP2UodCk6QShuZXcgaCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFtoLkVSUl9CQURfUkVRVUVTVCxoLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciBXdD1GLmlzU3RhbmRhcmRCcm93c2VyRW52P2Z1bmN0aW9uKCl7cmV0dXJue3dyaXRlOmZ1bmN0aW9uKHQscixhLG8saSxsKXtsZXQgZj1bXTtmLnB1c2godCsiPSIrZW5jb2RlVVJJQ29tcG9uZW50KHIpKSxjLmlzTnVtYmVyKGEpJiZmLnB1c2goImV4cGlyZXM9IituZXcgRGF0ZShhKS50b0dNVFN0cmluZygpKSxjLmlzU3RyaW5nKG8pJiZmLnB1c2goInBhdGg9IitvKSxjLmlzU3RyaW5nKGkpJiZmLnB1c2goImRvbWFpbj0iK2kpLGw9PT0hMCYmZi5wdXNoKCJzZWN1cmUiKSxkb2N1bWVudC5jb29raWU9Zi5qb2luKCI7ICIpfSxyZWFkOmZ1bmN0aW9uKHQpe2xldCByPWRvY3VtZW50LmNvb2tpZS5tYXRjaChuZXcgUmVnRXhwKCIoXnw7XFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIHI/ZGVjb2RlVVJJQ29tcG9uZW50KHJbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBWZShlKXtyZXR1cm4vXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KGUpfWZ1bmN0aW9uIFplKGUsQSl7cmV0dXJuIEE/ZS5yZXBsYWNlKC9cLyskLywiIikrIi8iK0EucmVwbGFjZSgvXlwvKy8sIiIpOmV9ZnVuY3Rpb24gZ2UoZSxBKXtyZXR1cm4gZSYmIVZlKEEpP1plKGUsQSk6QX12YXIgTnQ9Ri5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBBPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikscjtmdW5jdGlvbiBhKG8pe2xldCBpPW87cmV0dXJuIEEmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsaSksaT10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixpKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cPy8sIiIpOiIiLGhhc2g6dC5oYXNoP3QuaGFzaC5yZXBsYWNlKC9eIy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIHI9YSh3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oaSl7bGV0IGw9Yy5pc1N0cmluZyhpKT9hKGkpOmk7cmV0dXJuIGwucHJvdG9jb2w9PT1yLnByb3RvY29sJiZsLmhvc3Q9PT1yLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIFhlKGUpe2xldCBBPS9eKFstK1x3XXsxLDI1fSkoOj9cL1wvfDopLy5leGVjKGUpO3JldHVybiBBJiZBWzFdfHwiIn1mdW5jdGlvbiBiaShlLEEpe2U9ZXx8MTA7bGV0IHQ9bmV3IEFycmF5KGUpLHI9bmV3IEFycmF5KGUpLGE9MCxvPTAsaTtyZXR1cm4gQT1BIT09dm9pZCAwP0E6MWUzLGZ1bmN0aW9uKGYpe2xldCBnPURhdGUubm93KCksbj1yW29dO2l8fChpPWcpLHRbYV09ZixyW2FdPWc7bGV0IHU9byxwPTA7Zm9yKDt1IT09YTspcCs9dFt1KytdLHU9dSVlO2lmKGE9KGErMSklZSxhPT09byYmKG89KG8rMSklZSksZy1pPEEpcmV0dXJuO2xldCBzPW4mJmctbjtyZXR1cm4gcz9NYXRoLnJvdW5kKHAqMWUzL3MpOnZvaWQgMH19dmFyIFB0PWJpO2Z1bmN0aW9uIHh0KGUsQSl7bGV0IHQ9MCxyPVB0KDUwLDI1MCk7cmV0dXJuIGE9PntsZXQgbz1hLmxvYWRlZCxpPWEubGVuZ3RoQ29tcHV0YWJsZT9hLnRvdGFsOnZvaWQgMCxsPW8tdCxmPXIobCksZz1vPD1pO3Q9bztsZXQgbj17bG9hZGVkOm8sdG90YWw6aSxwcm9ncmVzczppP28vaTp2b2lkIDAsYnl0ZXM6bCxyYXRlOmZ8fHZvaWQgMCxlc3RpbWF0ZWQ6ZiYmaSYmZz8oaS1vKS9mOnZvaWQgMCxldmVudDphfTtuW0E/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsZShuKX19dmFyIGtpPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsR3Q9a2kmJmZ1bmN0aW9uKGUpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LHIpe2xldCBhPWUuZGF0YSxvPVUuZnJvbShlLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGk9ZS5yZXNwb25zZVR5cGUsbDtmdW5jdGlvbiBmKCl7ZS5jYW5jZWxUb2tlbiYmZS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShsKSxlLnNpZ25hbCYmZS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGwpfWxldCBnO2MuaXNGb3JtRGF0YShhKSYmKEYuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEYuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/by5zZXRDb250ZW50VHlwZSghMSk6by5nZXRDb250ZW50VHlwZSgvXlxzKm11bHRpcGFydFwvZm9ybS1kYXRhLyk/Yy5pc1N0cmluZyhnPW8uZ2V0Q29udGVudFR5cGUoKSkmJm8uc2V0Q29udGVudFR5cGUoZy5yZXBsYWNlKC9eXHMqKG11bHRpcGFydFwvZm9ybS1kYXRhKTsrLywiJDEiKSk6by5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YSIpKTtsZXQgbj1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoZS5hdXRoKXtsZXQgST1lLmF1dGgudXNlcm5hbWV8fCIiLGQ9ZS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChlLmF1dGgucGFzc3dvcmQpKToiIjtvLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYShJKyI6IitkKSl9bGV0IHU9Z2UoZS5iYXNlVVJMLGUudXJsKTtuLm9wZW4oZS5tZXRob2QudG9VcHBlckNhc2UoKSxuZSh1LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplciksITApLG4udGltZW91dD1lLnRpbWVvdXQ7ZnVuY3Rpb24gcCgpe2lmKCFuKXJldHVybjtsZXQgST1VLmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBuJiZuLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxFPXtkYXRhOiFpfHxpPT09InRleHQifHxpPT09Impzb24iP24ucmVzcG9uc2VUZXh0Om4ucmVzcG9uc2Usc3RhdHVzOm4uc3RhdHVzLHN0YXR1c1RleHQ6bi5zdGF0dXNUZXh0LGhlYWRlcnM6SSxjb25maWc6ZSxyZXF1ZXN0Om59O3plKGZ1bmN0aW9uKHcpe3QodyksZigpfSxmdW5jdGlvbih3KXtyKHcpLGYoKX0sRSksbj1udWxsfWlmKCJvbmxvYWRlbmQiaW4gbj9uLm9ubG9hZGVuZD1wOm4ub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IW58fG4ucmVhZHlTdGF0ZSE9PTR8fG4uc3RhdHVzPT09MCYmIShuLnJlc3BvbnNlVVJMJiZuLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChwKX0sbi5vbmFib3J0PWZ1bmN0aW9uKCl7biYmKHIobmV3IGgoIlJlcXVlc3QgYWJvcnRlZCIsaC5FQ09OTkFCT1JURUQsZSxuKSksbj1udWxsKX0sbi5vbmVycm9yPWZ1bmN0aW9uKCl7cihuZXcgaCgiTmV0d29yayBFcnJvciIsaC5FUlJfTkVUV09SSyxlLG4pKSxuPW51bGx9LG4ub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IGQ9ZS50aW1lb3V0PyJ0aW1lb3V0IG9mICIrZS50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLEU9ZS50cmFuc2l0aW9uYWx8fEVlO2UudGltZW91dEVycm9yTWVzc2FnZSYmKGQ9ZS50aW1lb3V0RXJyb3JNZXNzYWdlKSxyKG5ldyBoKGQsRS5jbGFyaWZ5VGltZW91dEVycm9yP2guRVRJTUVET1VUOmguRUNPTk5BQk9SVEVELGUsbikpLG49bnVsbH0sRi5pc1N0YW5kYXJkQnJvd3NlckVudil7bGV0IEk9TnQodSkmJmUueHNyZkNvb2tpZU5hbWUmJld0LnJlYWQoZS54c3JmQ29va2llTmFtZSk7SSYmby5zZXQoZS54c3JmSGVhZGVyTmFtZSxJKX1hPT09dm9pZCAwJiZvLnNldENvbnRlbnRUeXBlKG51bGwpLCJzZXRSZXF1ZXN0SGVhZGVyImluIG4mJmMuZm9yRWFjaChvLnRvSlNPTigpLGZ1bmN0aW9uKGQsRSl7bi5zZXRSZXF1ZXN0SGVhZGVyKEUsZCl9KSxjLmlzVW5kZWZpbmVkKGUud2l0aENyZWRlbnRpYWxzKXx8KG4ud2l0aENyZWRlbnRpYWxzPSEhZS53aXRoQ3JlZGVudGlhbHMpLGkmJmkhPT0ianNvbiImJihuLnJlc3BvbnNlVHlwZT1lLnJlc3BvbnNlVHlwZSksdHlwZW9mIGUub25Eb3dubG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZuLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIix4dChlLm9uRG93bmxvYWRQcm9ncmVzcywhMCkpLHR5cGVvZiBlLm9uVXBsb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm4udXBsb2FkJiZuLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIseHQoZS5vblVwbG9hZFByb2dyZXNzKSksKGUuY2FuY2VsVG9rZW58fGUuc2lnbmFsKSYmKGw9ST0+e24mJihyKCFJfHxJLnR5cGU/bmV3IEwobnVsbCxlLG4pOkkpLG4uYWJvcnQoKSxuPW51bGwpfSxlLmNhbmNlbFRva2VuJiZlLmNhbmNlbFRva2VuLnN1YnNjcmliZShsKSxlLnNpZ25hbCYmKGUuc2lnbmFsLmFib3J0ZWQ/bCgpOmUuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixsKSkpO2xldCBzPVhlKHUpO2lmKHMmJkYucHJvdG9jb2xzLmluZGV4T2Yocyk9PT0tMSl7cihuZXcgaCgiVW5zdXBwb3J0ZWQgcHJvdG9jb2wgIitzKyI6IixoLkVSUl9CQURfUkVRVUVTVCxlKSk7cmV0dXJufW4uc2VuZChhfHxudWxsKX0pfTt2YXIgJGU9e2h0dHA6Q2UseGhyOkd0fTtjLmZvckVhY2goJGUsKGUsQSk9PntpZihlKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIm5hbWUiLHt2YWx1ZTpBfSl9Y2F0Y2h7fU9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJhZGFwdGVyTmFtZSIse3ZhbHVlOkF9KX19KTt2YXIgVHQ9ZT0+YC0gJHtlfWAsRGk9ZT0+Yy5pc0Z1bmN0aW9uKGUpfHxlPT09bnVsbHx8ZT09PSExLHdlPXtnZXRBZGFwdGVyOmU9PntlPWMuaXNBcnJheShlKT9lOltlXTtsZXR7bGVuZ3RoOkF9PWUsdCxyLGE9e307Zm9yKGxldCBvPTA7bzxBO28rKyl7dD1lW29dO2xldCBpO2lmKHI9dCwhRGkodCkmJihyPSRlWyhpPVN0cmluZyh0KSkudG9Mb3dlckNhc2UoKV0scj09PXZvaWQgMCkpdGhyb3cgbmV3IGgoYFVua25vd24gYWRhcHRlciAnJHtpfSdgKTtpZihyKWJyZWFrO2FbaXx8IiMiK29dPXJ9aWYoIXIpe2xldCBvPU9iamVjdC5lbnRyaWVzKGEpLm1hcCgoW2wsZl0pPT5gYWRhcHRlciAke2x9IGArKGY9PT0hMT8iaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZW52aXJvbm1lbnQiOiJpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZCIpKSxpPUE/by5sZW5ndGg+MT9gc2luY2UgOgpgK28ubWFwKFR0KS5qb2luKGAKYCk6IiAiK1R0KG9bMF0pOiJhcyBubyBhZGFwdGVyIHNwZWNpZmllZCI7dGhyb3cgbmV3IGgoIlRoZXJlIGlzIG5vIHN1aXRhYmxlIGFkYXB0ZXIgdG8gZGlzcGF0Y2ggdGhlIHJlcXVlc3QgIitpLCJFUlJfTk9UX1NVUFBPUlQiKX1yZXR1cm4gcn0sYWRhcHRlcnM6JGV9O2Z1bmN0aW9uIGVBKGUpe2lmKGUuY2FuY2VsVG9rZW4mJmUuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLGUuc2lnbmFsJiZlLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyBMKG51bGwsZSl9ZnVuY3Rpb24gUmUoZSl7cmV0dXJuIGVBKGUpLGUuaGVhZGVycz1VLmZyb20oZS5oZWFkZXJzKSxlLmRhdGE9SWUuY2FsbChlLGUudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKGUubWV0aG9kKSE9PS0xJiZlLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLHdlLmdldEFkYXB0ZXIoZS5hZGFwdGVyfHx6LmFkYXB0ZXIpKGUpLnRoZW4oZnVuY3Rpb24ocil7cmV0dXJuIGVBKGUpLHIuZGF0YT1JZS5jYWxsKGUsZS50cmFuc2Zvcm1SZXNwb25zZSxyKSxyLmhlYWRlcnM9VS5mcm9tKHIuaGVhZGVycykscn0sZnVuY3Rpb24ocil7cmV0dXJuIGxlKHIpfHwoZUEoZSksciYmci5yZXNwb25zZSYmKHIucmVzcG9uc2UuZGF0YT1JZS5jYWxsKGUsZS50cmFuc2Zvcm1SZXNwb25zZSxyLnJlc3BvbnNlKSxyLnJlc3BvbnNlLmhlYWRlcnM9VS5mcm9tKHIucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChyKX0pfXZhciBKdD1lPT5lIGluc3RhbmNlb2YgVT9lLnRvSlNPTigpOmU7ZnVuY3Rpb24gRyhlLEEpe0E9QXx8e307bGV0IHQ9e307ZnVuY3Rpb24gcihnLG4sdSl7cmV0dXJuIGMuaXNQbGFpbk9iamVjdChnKSYmYy5pc1BsYWluT2JqZWN0KG4pP2MubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6dX0sZyxuKTpjLmlzUGxhaW5PYmplY3Qobik/Yy5tZXJnZSh7fSxuKTpjLmlzQXJyYXkobik/bi5zbGljZSgpOm59ZnVuY3Rpb24gYShnLG4sdSl7aWYoYy5pc1VuZGVmaW5lZChuKSl7aWYoIWMuaXNVbmRlZmluZWQoZykpcmV0dXJuIHIodm9pZCAwLGcsdSl9ZWxzZSByZXR1cm4gcihnLG4sdSl9ZnVuY3Rpb24gbyhnLG4pe2lmKCFjLmlzVW5kZWZpbmVkKG4pKXJldHVybiByKHZvaWQgMCxuKX1mdW5jdGlvbiBpKGcsbil7aWYoYy5pc1VuZGVmaW5lZChuKSl7aWYoIWMuaXNVbmRlZmluZWQoZykpcmV0dXJuIHIodm9pZCAwLGcpfWVsc2UgcmV0dXJuIHIodm9pZCAwLG4pfWZ1bmN0aW9uIGwoZyxuLHUpe2lmKHUgaW4gQSlyZXR1cm4gcihnLG4pO2lmKHUgaW4gZSlyZXR1cm4gcih2b2lkIDAsZyl9bGV0IGY9e3VybDpvLG1ldGhvZDpvLGRhdGE6byxiYXNlVVJMOmksdHJhbnNmb3JtUmVxdWVzdDppLHRyYW5zZm9ybVJlc3BvbnNlOmkscGFyYW1zU2VyaWFsaXplcjppLHRpbWVvdXQ6aSx0aW1lb3V0TWVzc2FnZTppLHdpdGhDcmVkZW50aWFsczppLGFkYXB0ZXI6aSxyZXNwb25zZVR5cGU6aSx4c3JmQ29va2llTmFtZTppLHhzcmZIZWFkZXJOYW1lOmksb25VcGxvYWRQcm9ncmVzczppLG9uRG93bmxvYWRQcm9ncmVzczppLGRlY29tcHJlc3M6aSxtYXhDb250ZW50TGVuZ3RoOmksbWF4Qm9keUxlbmd0aDppLGJlZm9yZVJlZGlyZWN0OmksdHJhbnNwb3J0OmksaHR0cEFnZW50OmksaHR0cHNBZ2VudDppLGNhbmNlbFRva2VuOmksc29ja2V0UGF0aDppLHJlc3BvbnNlRW5jb2Rpbmc6aSx2YWxpZGF0ZVN0YXR1czpsLGhlYWRlcnM6KGcsbik9PmEoSnQoZyksSnQobiksITApfTtyZXR1cm4gYy5mb3JFYWNoKE9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30sZSxBKSksZnVuY3Rpb24obil7bGV0IHU9ZltuXXx8YSxwPXUoZVtuXSxBW25dLG4pO2MuaXNVbmRlZmluZWQocCkmJnUhPT1sfHwodFtuXT1wKX0pLHR9dmFyIGJlPSIxLjYuMCI7dmFyIEFBPXt9O1sib2JqZWN0IiwiYm9vbGVhbiIsIm51bWJlciIsImZ1bmN0aW9uIiwic3RyaW5nIiwic3ltYm9sIl0uZm9yRWFjaCgoZSxBKT0+e0FBW2VdPWZ1bmN0aW9uKHIpe3JldHVybiB0eXBlb2Ygcj09PWV8fCJhIisoQTwxPyJuICI6IiAiKStlfX0pO3ZhciBMdD17fTtBQS50cmFuc2l0aW9uYWw9ZnVuY3Rpb24oQSx0LHIpe2Z1bmN0aW9uIGEobyxpKXtyZXR1cm4iW0F4aW9zIHYiK2JlKyJdIFRyYW5zaXRpb25hbCBvcHRpb24gJyIrbysiJyIraSsocj8iLiAiK3I6IiIpfXJldHVybihvLGksbCk9PntpZihBPT09ITEpdGhyb3cgbmV3IGgoYShpLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKHQ/IiBpbiAiK3Q6IiIpKSxoLkVSUl9ERVBSRUNBVEVEKTtyZXR1cm4gdCYmIUx0W2ldJiYoTHRbaV09ITAsY29uc29sZS53YXJuKGEoaSwiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrdCsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSxBP0EobyxpLGwpOiEwfX07ZnVuY3Rpb24gRmkoZSxBLHQpe2lmKHR5cGVvZiBlIT0ib2JqZWN0Iil0aHJvdyBuZXcgaCgib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIsaC5FUlJfQkFEX09QVElPTl9WQUxVRSk7bGV0IHI9T2JqZWN0LmtleXMoZSksYT1yLmxlbmd0aDtmb3IoO2EtLSA+MDspe2xldCBvPXJbYV0saT1BW29dO2lmKGkpe2xldCBsPWVbb10sZj1sPT09dm9pZCAwfHxpKGwsbyxlKTtpZihmIT09ITApdGhyb3cgbmV3IGgoIm9wdGlvbiAiK28rIiBtdXN0IGJlICIrZixoLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgbmV3IGgoIlVua25vd24gb3B0aW9uICIrbyxoLkVSUl9CQURfT1BUSU9OKX19dmFyIGtlPXthc3NlcnRPcHRpb25zOkZpLHZhbGlkYXRvcnM6QUF9O3ZhciBNPWtlLnZhbGlkYXRvcnMsWj1jbGFzc3tjb25zdHJ1Y3RvcihBKXt0aGlzLmRlZmF1bHRzPUEsdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IHZlLHJlc3BvbnNlOm5ldyB2ZX19cmVxdWVzdChBLHQpe3R5cGVvZiBBPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1BKTp0PUF8fHt9LHQ9Ryh0aGlzLmRlZmF1bHRzLHQpO2xldHt0cmFuc2l0aW9uYWw6cixwYXJhbXNTZXJpYWxpemVyOmEsaGVhZGVyczpvfT10O3IhPT12b2lkIDAmJmtlLmFzc2VydE9wdGlvbnMocix7c2lsZW50SlNPTlBhcnNpbmc6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpNLnRyYW5zaXRpb25hbChNLmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKX0sITEpLGEhPW51bGwmJihjLmlzRnVuY3Rpb24oYSk/dC5wYXJhbXNTZXJpYWxpemVyPXtzZXJpYWxpemU6YX06a2UuYXNzZXJ0T3B0aW9ucyhhLHtlbmNvZGU6TS5mdW5jdGlvbixzZXJpYWxpemU6TS5mdW5jdGlvbn0sITApKSx0Lm1ldGhvZD0odC5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgaT1vJiZjLm1lcmdlKG8uY29tbW9uLG9bdC5tZXRob2RdKTtvJiZjLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sST0+e2RlbGV0ZSBvW0ldfSksdC5oZWFkZXJzPVUuY29uY2F0KGksbyk7bGV0IGw9W10sZj0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZCl7dHlwZW9mIGQucnVuV2hlbj09ImZ1bmN0aW9uIiYmZC5ydW5XaGVuKHQpPT09ITF8fChmPWYmJmQuc3luY2hyb25vdXMsbC51bnNoaWZ0KGQuZnVsZmlsbGVkLGQucmVqZWN0ZWQpKX0pO2xldCBnPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZCl7Zy5wdXNoKGQuZnVsZmlsbGVkLGQucmVqZWN0ZWQpfSk7bGV0IG4sdT0wLHA7aWYoIWYpe2xldCBJPVtSZS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKEkudW5zaGlmdC5hcHBseShJLGwpLEkucHVzaC5hcHBseShJLGcpLHA9SS5sZW5ndGgsbj1Qcm9taXNlLnJlc29sdmUodCk7dTxwOyluPW4udGhlbihJW3UrK10sSVt1KytdKTtyZXR1cm4gbn1wPWwubGVuZ3RoO2xldCBzPXQ7Zm9yKHU9MDt1PHA7KXtsZXQgST1sW3UrK10sZD1sW3UrK107dHJ5e3M9SShzKX1jYXRjaChFKXtkLmNhbGwodGhpcyxFKTticmVha319dHJ5e249UmUuY2FsbCh0aGlzLHMpfWNhdGNoKEkpe3JldHVybiBQcm9taXNlLnJlamVjdChJKX1mb3IodT0wLHA9Zy5sZW5ndGg7dTxwOyluPW4udGhlbihnW3UrK10sZ1t1KytdKTtyZXR1cm4gbn1nZXRVcmkoQSl7QT1HKHRoaXMuZGVmYXVsdHMsQSk7bGV0IHQ9Z2UoQS5iYXNlVVJMLEEudXJsKTtyZXR1cm4gbmUodCxBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpfX07Yy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihBKXtaLnByb3RvdHlwZVtBXT1mdW5jdGlvbih0LHIpe3JldHVybiB0aGlzLnJlcXVlc3QoRyhyfHx7fSx7bWV0aG9kOkEsdXJsOnQsZGF0YToocnx8e30pLmRhdGF9KSl9fSk7Yy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oQSl7ZnVuY3Rpb24gdChyKXtyZXR1cm4gZnVuY3Rpb24obyxpLGwpe3JldHVybiB0aGlzLnJlcXVlc3QoRyhsfHx7fSx7bWV0aG9kOkEsaGVhZGVyczpyP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDpvLGRhdGE6aX0pKX19Wi5wcm90b3R5cGVbQV09dCgpLFoucHJvdG90eXBlW0ErIkZvcm0iXT10KCEwKX0pO3ZhciBwZT1aO3ZhciB0QT1jbGFzcyBle2NvbnN0cnVjdG9yKEEpe2lmKHR5cGVvZiBBIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24obyl7dD1vfSk7bGV0IHI9dGhpczt0aGlzLnByb21pc2UudGhlbihhPT57aWYoIXIuX2xpc3RlbmVycylyZXR1cm47bGV0IG89ci5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO28tLSA+MDspci5fbGlzdGVuZXJzW29dKGEpO3IuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49YT0+e2xldCBvLGk9bmV3IFByb21pc2UobD0+e3Iuc3Vic2NyaWJlKGwpLG89bH0pLnRoZW4oYSk7cmV0dXJuIGkuY2FuY2VsPWZ1bmN0aW9uKCl7ci51bnN1YnNjcmliZShvKX0saX0sQShmdW5jdGlvbihvLGksbCl7ci5yZWFzb258fChyLnJlYXNvbj1uZXcgTChvLGksbCksdChyLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShBKXtpZih0aGlzLnJlYXNvbil7QSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChBKTp0aGlzLl9saXN0ZW5lcnM9W0FdfXVuc3Vic2NyaWJlKEEpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKEEpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgQTtyZXR1cm57dG9rZW46bmV3IGUoZnVuY3Rpb24oYSl7QT1hfSksY2FuY2VsOkF9fX0sTXQ9dEE7ZnVuY3Rpb24gckEoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBlLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGlBKGUpe3JldHVybiBjLmlzT2JqZWN0KGUpJiZlLmlzQXhpb3NFcnJvcj09PSEwfXZhciBhQT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXMoYUEpLmZvckVhY2goKFtlLEFdKT0+e2FBW0FdPWV9KTt2YXIgSHQ9YUE7ZnVuY3Rpb24gWXQoZSl7bGV0IEE9bmV3IHBlKGUpLHQ9aWUocGUucHJvdG90eXBlLnJlcXVlc3QsQSk7cmV0dXJuIGMuZXh0ZW5kKHQscGUucHJvdG90eXBlLEEse2FsbE93bktleXM6ITB9KSxjLmV4dGVuZCh0LEEsbnVsbCx7YWxsT3duS2V5czohMH0pLHQuY3JlYXRlPWZ1bmN0aW9uKGEpe3JldHVybiBZdChHKGUsYSkpfSx0fXZhciBiPVl0KHopO2IuQXhpb3M9cGU7Yi5DYW5jZWxlZEVycm9yPUw7Yi5DYW5jZWxUb2tlbj1NdDtiLmlzQ2FuY2VsPWxlO2IuVkVSU0lPTj1iZTtiLnRvRm9ybURhdGE9SjtiLkF4aW9zRXJyb3I9aDtiLkNhbmNlbD1iLkNhbmNlbGVkRXJyb3I7Yi5hbGw9ZnVuY3Rpb24oQSl7cmV0dXJuIFByb21pc2UuYWxsKEEpfTtiLnNwcmVhZD1yQTtiLmlzQXhpb3NFcnJvcj1pQTtiLm1lcmdlQ29uZmlnPUc7Yi5BeGlvc0hlYWRlcnM9VTtiLmZvcm1Ub0pTT049ZT0+UWUoYy5pc0hUTUxGb3JtKGUpP25ldyBGb3JtRGF0YShlKTplKTtiLmdldEFkYXB0ZXI9d2UuZ2V0QWRhcHRlcjtiLkh0dHBTdGF0dXNDb2RlPUh0O2IuZGVmYXVsdD1iO3ZhciBZPWI7dmFye0F4aW9zOnNJLEF4aW9zRXJyb3I6SUksQ2FuY2VsZWRFcnJvcjpsSSxpc0NhbmNlbDpnSSxDYW5jZWxUb2tlbjpwSSxWRVJTSU9OOm1JLGFsbDp1SSxDYW5jZWw6ZkksaXNBeGlvc0Vycm9yOmNJLHNwcmVhZDpkSSx0b0Zvcm1EYXRhOkJJLEF4aW9zSGVhZGVyczpDSSxIdHRwU3RhdHVzQ29kZTp5SSxmb3JtVG9KU09OOkVJLGdldEFkYXB0ZXI6UUksbWVyZ2VDb25maWc6aEl9PVk7dmFyIHZ0PVN5bWJvbCgiQ29tbGluay5wcm94eSIpLE9pPVN5bWJvbCgiQ29tbGluay5lbmRwb2ludCIpLHNBPVN5bWJvbCgiQ29tbGluay5yZWxlYXNlUHJveHkiKSxvQT1TeW1ib2woIkNvbWxpbmsuZmluYWxpemVyIiksRmU9U3ltYm9sKCJDb21saW5rLnRocm93biIpLEt0PWU9PnR5cGVvZiBlPT0ib2JqZWN0IiYmZSE9PW51bGx8fHR5cGVvZiBlPT0iZnVuY3Rpb24iLFVpPXtjYW5IYW5kbGU6ZT0+S3QoZSkmJmVbdnRdLHNlcmlhbGl6ZShlKXtsZXR7cG9ydDE6QSxwb3J0Mjp0fT1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIF90KGUsQSksW3QsW3RdXX0sZGVzZXJpYWxpemUoZSl7cmV0dXJuIGUuc3RhcnQoKSxJQShlKX19LFNpPXtjYW5IYW5kbGU6ZT0+S3QoZSkmJkZlIGluIGUsc2VyaWFsaXplKHt2YWx1ZTplfSl7bGV0IEE7cmV0dXJuIGUgaW5zdGFuY2VvZiBFcnJvcj9BPXtpc0Vycm9yOiEwLHZhbHVlOnttZXNzYWdlOmUubWVzc2FnZSxuYW1lOmUubmFtZSxzdGFjazplLnN0YWNrfX06QT17aXNFcnJvcjohMSx2YWx1ZTplfSxbQSxbXV19LGRlc2VyaWFsaXplKGUpe3Rocm93IGUuaXNFcnJvcj9PYmplY3QuYXNzaWduKG5ldyBFcnJvcihlLnZhbHVlLm1lc3NhZ2UpLGUudmFsdWUpOmUudmFsdWV9fSxqdD1uZXcgTWFwKFtbInByb3h5IixVaV0sWyJ0aHJvdyIsU2ldXSk7ZnVuY3Rpb24gV2koZSxBKXtmb3IobGV0IHQgb2YgZSlpZihBPT09dHx8dD09PSIqInx8dCBpbnN0YW5jZW9mIFJlZ0V4cCYmdC50ZXN0KEEpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIF90KGUsQT1nbG9iYWxUaGlzLHQ9WyIqIl0pe0EuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gcihhKXtpZighYXx8IWEuZGF0YSlyZXR1cm47aWYoIVdpKHQsYS5vcmlnaW4pKXtjb25zb2xlLndhcm4oYEludmFsaWQgb3JpZ2luICcke2Eub3JpZ2lufScgZm9yIGNvbWxpbmsgcHJveHlgKTtyZXR1cm59bGV0e2lkOm8sdHlwZTppLHBhdGg6bH09T2JqZWN0LmFzc2lnbih7cGF0aDpbXX0sYS5kYXRhKSxmPShhLmRhdGEuYXJndW1lbnRMaXN0fHxbXSkubWFwKHEpLGc7dHJ5e2xldCBuPWwuc2xpY2UoMCwtMSkucmVkdWNlKChwLHMpPT5wW3NdLGUpLHU9bC5yZWR1Y2UoKHAscyk9PnBbc10sZSk7c3dpdGNoKGkpe2Nhc2UiR0VUIjpnPXU7YnJlYWs7Y2FzZSJTRVQiOm5bbC5zbGljZSgtMSlbMF1dPXEoYS5kYXRhLnZhbHVlKSxnPSEwO2JyZWFrO2Nhc2UiQVBQTFkiOmc9dS5hcHBseShuLGYpO2JyZWFrO2Nhc2UiQ09OU1RSVUNUIjp7bGV0IHA9bmV3IHUoLi4uZik7Zz1UaShwKX1icmVhaztjYXNlIkVORFBPSU5UIjp7bGV0e3BvcnQxOnAscG9ydDI6c309bmV3IE1lc3NhZ2VDaGFubmVsO190KGUscyksZz1sQShwLFtwXSl9YnJlYWs7Y2FzZSJSRUxFQVNFIjpnPXZvaWQgMDticmVhaztkZWZhdWx0OnJldHVybn19Y2F0Y2gobil7Zz17dmFsdWU6bixbRmVdOjB9fVByb21pc2UucmVzb2x2ZShnKS5jYXRjaChuPT4oe3ZhbHVlOm4sW0ZlXTowfSkpLnRoZW4obj0+e2xldFt1LHBdPVNlKG4pO0EucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LHUpLHtpZDpvfSkscCksaT09PSJSRUxFQVNFIiYmKEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsciksenQoQSksb0EgaW4gZSYmdHlwZW9mIGVbb0FdPT0iZnVuY3Rpb24iJiZlW29BXSgpKX0pLmNhdGNoKG49PntsZXRbdSxwXT1TZSh7dmFsdWU6bmV3IFR5cGVFcnJvcigiVW5zZXJpYWxpemFibGUgcmV0dXJuIHZhbHVlIiksW0ZlXTowfSk7QS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sdSkse2lkOm99KSxwKX0pfSksQS5zdGFydCYmQS5zdGFydCgpfWZ1bmN0aW9uIE5pKGUpe3JldHVybiBlLmNvbnN0cnVjdG9yLm5hbWU9PT0iTWVzc2FnZVBvcnQifWZ1bmN0aW9uIHp0KGUpe05pKGUpJiZlLmNsb3NlKCl9ZnVuY3Rpb24gSUEoZSxBKXtyZXR1cm4gbkEoZSxbXSxBKX1mdW5jdGlvbiBEZShlKXtpZihlKXRocm93IG5ldyBFcnJvcigiUHJveHkgaGFzIGJlZW4gcmVsZWFzZWQgYW5kIGlzIG5vdCB1c2VhYmxlIil9ZnVuY3Rpb24gVnQoZSl7cmV0dXJuIFgoZSx7dHlwZToiUkVMRUFTRSJ9KS50aGVuKCgpPT57enQoZSl9KX12YXIgT2U9bmV3IFdlYWtNYXAsVWU9IkZpbmFsaXphdGlvblJlZ2lzdHJ5ImluIGdsb2JhbFRoaXMmJm5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeShlPT57bGV0IEE9KE9lLmdldChlKXx8MCktMTtPZS5zZXQoZSxBKSxBPT09MCYmVnQoZSl9KTtmdW5jdGlvbiBQaShlLEEpe2xldCB0PShPZS5nZXQoQSl8fDApKzE7T2Uuc2V0KEEsdCksVWUmJlVlLnJlZ2lzdGVyKGUsQSxlKX1mdW5jdGlvbiB4aShlKXtVZSYmVWUudW5yZWdpc3RlcihlKX1mdW5jdGlvbiBuQShlLEE9W10sdD1mdW5jdGlvbigpe30pe2xldCByPSExLGE9bmV3IFByb3h5KHQse2dldChvLGkpe2lmKERlKHIpLGk9PT1zQSlyZXR1cm4oKT0+e3hpKGEpLFZ0KGUpLHI9ITB9O2lmKGk9PT0idGhlbiIpe2lmKEEubGVuZ3RoPT09MClyZXR1cm57dGhlbjooKT0+YX07bGV0IGw9WChlLHt0eXBlOiJHRVQiLHBhdGg6QS5tYXAoZj0+Zi50b1N0cmluZygpKX0pLnRoZW4ocSk7cmV0dXJuIGwudGhlbi5iaW5kKGwpfXJldHVybiBuQShlLFsuLi5BLGldKX0sc2V0KG8saSxsKXtEZShyKTtsZXRbZixnXT1TZShsKTtyZXR1cm4gWChlLHt0eXBlOiJTRVQiLHBhdGg6Wy4uLkEsaV0ubWFwKG49Pm4udG9TdHJpbmcoKSksdmFsdWU6Zn0sZykudGhlbihxKX0sYXBwbHkobyxpLGwpe0RlKHIpO2xldCBmPUFbQS5sZW5ndGgtMV07aWYoZj09PU9pKXJldHVybiBYKGUse3R5cGU6IkVORFBPSU5UIn0pLnRoZW4ocSk7aWYoZj09PSJiaW5kIilyZXR1cm4gbkEoZSxBLnNsaWNlKDAsLTEpKTtsZXRbZyxuXT1xdChsKTtyZXR1cm4gWChlLHt0eXBlOiJBUFBMWSIscGF0aDpBLm1hcCh1PT51LnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpnfSxuKS50aGVuKHEpfSxjb25zdHJ1Y3QobyxpKXtEZShyKTtsZXRbbCxmXT1xdChpKTtyZXR1cm4gWChlLHt0eXBlOiJDT05TVFJVQ1QiLHBhdGg6QS5tYXAoZz0+Zy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6bH0sZikudGhlbihxKX19KTtyZXR1cm4gUGkoYSxlKSxhfWZ1bmN0aW9uIEdpKGUpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLGUpfWZ1bmN0aW9uIHF0KGUpe2xldCBBPWUubWFwKFNlKTtyZXR1cm5bQS5tYXAodD0+dFswXSksR2koQS5tYXAodD0+dFsxXSkpXX12YXIgWnQ9bmV3IFdlYWtNYXA7ZnVuY3Rpb24gbEEoZSxBKXtyZXR1cm4gWnQuc2V0KGUsQSksZX1mdW5jdGlvbiBUaShlKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihlLHtbdnRdOiEwfSl9ZnVuY3Rpb24gU2UoZSl7Zm9yKGxldFtBLHRdb2YganQpaWYodC5jYW5IYW5kbGUoZSkpe2xldFtyLGFdPXQuc2VyaWFsaXplKGUpO3JldHVyblt7dHlwZToiSEFORExFUiIsbmFtZTpBLHZhbHVlOnJ9LGFdfXJldHVyblt7dHlwZToiUkFXIix2YWx1ZTplfSxadC5nZXQoZSl8fFtdXX1mdW5jdGlvbiBxKGUpe3N3aXRjaChlLnR5cGUpe2Nhc2UiSEFORExFUiI6cmV0dXJuIGp0LmdldChlLm5hbWUpLmRlc2VyaWFsaXplKGUudmFsdWUpO2Nhc2UiUkFXIjpyZXR1cm4gZS52YWx1ZX19ZnVuY3Rpb24gWChlLEEsdCl7cmV0dXJuIG5ldyBQcm9taXNlKHI9PntsZXQgYT1KaSgpO2UuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gbyhpKXshaS5kYXRhfHwhaS5kYXRhLmlkfHxpLmRhdGEuaWQhPT1hfHwoZS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixvKSxyKGkuZGF0YSkpfSksZS5zdGFydCYmZS5zdGFydCgpLGUucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbih7aWQ6YX0sQSksdCl9KX1mdW5jdGlvbiBKaSgpe3JldHVybiBuZXcgQXJyYXkoNCkuZmlsbCgwKS5tYXAoKCk9Pk1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikudG9TdHJpbmcoMTYpKS5qb2luKCItIil9ZnVuY3Rpb24gJHQoZSl7bGV0IEE9SUEoZSksdD1lO3JldHVybiB0LndvcmtlclByb3h5PUEsdC5vcmlnaW5hbFRlcm1pbmF0ZT10LnRlcm1pbmF0ZSx0LnRlcm1pbmF0ZT0oKT0+e3Qud29ya2VyUHJveHlbc0FdKCksdC5vcmlnaW5hbFRlcm1pbmF0ZSgpfSx7d29ya2VyUHJveHk6QSx3b3JrZXI6dH19YXN5bmMgZnVuY3Rpb24gTGkoZSxBKXtsZXQgdDtpZihlIT1udWxsKXtsZXQgaT1lO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyh0PWkud29ya2VyUHJveHkse3dvcmtlclByb3h5OnQsd29ya2VyOml9KTokdChlKX1sZXQgcj10eXBlb2YgQT4idSI/di5waXBlbGluZVdvcmtlclVybDpBLGE9bnVsbCxvPXYud2ViV29ya2Vyc1VybDtpZih0eXBlb2YgbzwidSIpe2NvbnNvbGUud2FybigiaXRrQ29uZmlnIHdlYldvcmtlcnNVcmwgaXMgZGVwcmVjYXRlZC4gUGxlYXNlIHVzZSBwaXBlbGluZVdvcmtlclVybCB3aXRoIHRoZSBmdWxsIHBhdGggdG8gdGhlIHBpcGVsaW5lIHdvcmtlci4iKTtsZXQgaT0ibWluLiIsbD1vO2lmKGwuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgZj1hd2FpdCBZLmdldChgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHtyZXNwb25zZVR5cGU6ImJsb2IifSksZz1VUkwuY3JlYXRlT2JqZWN0VVJMKGYuZGF0YSk7YT1uZXcgV29ya2VyKGcse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIGE9bmV3IFdvcmtlcihgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBpZihyPT09bnVsbClhPW5ldyBXb3JrZXIobmV3IFVSTCgiLi93ZWItd29ya2Vycy9pdGstd2FzbS1waXBlbGluZS53b3JrZXIuanMiLGltcG9ydC5tZXRhLnVybCkse3R5cGU6Im1vZHVsZSJ9KTtlbHNlIGlmKHIuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgaT1hd2FpdCBZLmdldChyLHtyZXNwb25zZVR5cGU6ImJsb2IifSksbD1VUkwuY3JlYXRlT2JqZWN0VVJMKGkuZGF0YSk7YT1uZXcgV29ya2VyKGwse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIGE9bmV3IFdvcmtlcihyLHt0eXBlOiJtb2R1bGUifSk7cmV0dXJuICR0KGEpfXZhciBlcj1MaTt2YXIgTWk7ZnVuY3Rpb24gQXIoKXtyZXR1cm4gTWl9dmFyIEhpO2Z1bmN0aW9uIHRyKCl7cmV0dXJuIEhpfWZ1bmN0aW9uIFlpKGUpe2xldCBBPWUuc2xpY2UoKGUubGFzdEluZGV4T2YoIi4iKS0xPj4+MCkrMik7aWYoQS50b0xvd2VyQ2FzZSgpPT09Imd6Iil7bGV0IHQ9ZS5zbGljZSgwLC0zKS5sYXN0SW5kZXhPZigiLiIpO0E9ZS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihBLnRvTG93ZXJDYXNlKCk9PT0iY2JvciIpe2xldCB0PWUuc2xpY2UoMCwtNSkubGFzdEluZGV4T2YoIi4iKTtBPWUuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoQS50b0xvd2VyQ2FzZSgpPT09InpzdCIpe2xldCB0PWUuc2xpY2UoMCwtMTApLmxhc3RJbmRleE9mKCIuIik7QT1lLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKEEudG9Mb3dlckNhc2UoKT09PSJ6aXAiKXtsZXQgdD1lLnNsaWNlKDAsLTQpLmxhc3RJbmRleE9mKCIuIik7QT1lLnNsaWNlKCh0LTE+Pj4wKSsyKX1yZXR1cm4gQX12YXIgbWU9WWk7ZnVuY3Rpb24gcWkoZSl7cmV0dXJuW2UuZGF0YSxlLmRpcmVjdGlvbl19dmFyIGdBPXFpO2Z1bmN0aW9uIHZpKGUpe3JldHVybltlLnBvaW50cyxlLnBvaW50RGF0YSxlLmNlbGxzLGUuY2VsbERhdGFdfXZhciBycj12aTthc3luYyBmdW5jdGlvbiBLaShlLEEpe2xldCB0PSJ1bmtub3duIjt0eXBlb2YgZSE9InN0cmluZyI/dD1lLmhyZWY6ZS5zdGFydHNXaXRoKCJodHRwIik/dD1lOnQ9YCR7QX0vJHtlfWAsdC5lbmRzV2l0aCgiLmpzIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtMykpLHQuZW5kc1dpdGgoIi53YXNtIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtNSkpO2xldCByPWAke3R9Lndhc21gLG89KGF3YWl0IFkuZ2V0KHIse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIifSkpLmRhdGE7cmV0dXJuKGF3YWl0IGltcG9ydChgJHt0fS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5Om99KX12YXIgaXI9S2k7dmFyIGFyPWFzeW5jKCk9PldlYkFzc2VtYmx5LnZhbGlkYXRlKG5ldyBVaW50OEFycmF5KFswLDk3LDExNSwxMDksMSwwLDAsMCwxLDUsMSw5NiwwLDEsMTIzLDMsMiwxLDAsMTAsMTAsMSw4LDAsNjUsMCwyNTMsMTUsMjUzLDk4LDExXSkpO3ZhciBzcj10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixvcj1uZXcgVGV4dEVuY29kZXIsbnI9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoZSxBKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxyPWUuZnNfb3BlbihBLHQuZmxhZ3MpLG89ZS5mc19zdGF0KEEpLnNpemUsaT1udWxsO3NyP2k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKG8pOmk9bmV3IEFycmF5QnVmZmVyKG8pO2xldCBsPW5ldyBVaW50OEFycmF5KGkpO3JldHVybiBlLmZzX3JlYWQocixsLDAsbywwKSxlLmZzX2Nsb3NlKHIpLGx9ZnVuY3Rpb24gSXIoZSxBLHQpe2xldCByPW51bGw7c3I/cj1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6cj1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IGE9bmV3IFVpbnQ4QXJyYXkociksbz1uZXcgVWludDhBcnJheShlLkhFQVBVOC5idWZmZXIsQSx0KTtyZXR1cm4gYS5zZXQobyksYX1mdW5jdGlvbiBPKGUsQSx0LHIpe2xldCBhPTA7cmV0dXJuIEEhPT1udWxsJiYoYT1lLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LHIsQS5idWZmZXIuYnl0ZUxlbmd0aF0pLGUuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShBLmJ1ZmZlciksYSkpLGF9ZnVuY3Rpb24gJChlLEEsdCl7bGV0IHI9SlNPTi5zdHJpbmdpZnkoQSksYT1lLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsci5sZW5ndGhdKTtlLndyaXRlQXNjaWlUb01lbW9yeShyLGEsITEpfWZ1bmN0aW9uIE4oZSxBLHQscil7bGV0IGE9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQSx0XSksbz1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxBLHRdKSxpPUlyKGUsYSxvKTtyZXR1cm4gRChyLGkuYnVmZmVyKX1mdW5jdGlvbiBwQShlLEEpe2xldCB0PWUuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsQV0pLHI9ZS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKHIpfWZ1bmN0aW9uIGppKGUsQSx0LHIpe3IhPW51bGwmJnIubGVuZ3RoPjAmJnIuZm9yRWFjaChmdW5jdGlvbihnLG4pe3ZhciB1O3N3aXRjaChnLnR5cGUpe2Nhc2UgbS5UZXh0U3RyZWFtOntsZXQgcD1vci5lbmNvZGUoZy5kYXRhLmRhdGEpLHM9TyhlLHAsbiwwKSxJPXtzaXplOnAuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3N9YH07JChlLEksbik7YnJlYWt9Y2FzZSBtLkpzb25Db21wYXRpYmxlOntsZXQgcD1vci5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoZy5kYXRhKSkscz1PKGUscCxuLDApLEk9e3NpemU6cC5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7c31gfTskKGUsSSxuKTticmVha31jYXNlIG0uQmluYXJ5U3RyZWFtOntsZXQgcD1nLmRhdGEuZGF0YSxzPU8oZSxwLG4sMCksST17c2l6ZTpwLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWB9OyQoZSxJLG4pO2JyZWFrfWNhc2UgbS5UZXh0RmlsZTp7ZS5mc193cml0ZUZpbGUoZy5kYXRhLnBhdGgsZy5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgbS5CaW5hcnlGaWxlOntlLmZzX3dyaXRlRmlsZShnLmRhdGEucGF0aCxnLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBtLkltYWdlOntsZXQgcD1nLmRhdGEscz1PKGUscC5kYXRhLG4sMCksST1PKGUscC5kaXJlY3Rpb24sbiwxKSxkPXR5cGVvZigodT1wLm1ldGFkYXRhKT09PW51bGx8fHU9PT12b2lkIDA/dm9pZCAwOnUuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20ocC5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLEU9e2ltYWdlVHlwZTpwLmltYWdlVHlwZSxuYW1lOnAubmFtZSxvcmlnaW46cC5vcmlnaW4sc3BhY2luZzpwLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLHNpemU6cC5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWAsbWV0YWRhdGE6ZH07JChlLEUsbik7YnJlYWt9Y2FzZSBtLk1lc2g6e2xldCBwPWcuZGF0YSxzPU8oZSxwLnBvaW50cyxuLDApLEk9TyhlLHAuY2VsbHMsbiwxKSxkPU8oZSxwLnBvaW50RGF0YSxuLDIpLEU9TyhlLHAuY2VsbERhdGEsbiwzKSxSPXttZXNoVHlwZTpwLm1lc2hUeXBlLG5hbWU6cC5uYW1lLG51bWJlck9mUG9pbnRzOnAubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7c31gLG51bWJlck9mQ2VsbHM6cC5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLGNlbGxCdWZmZXJTaXplOnAuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpwLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7ZH1gLG51bWJlck9mQ2VsbFBpeGVsczpwLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YH07JChlLFIsbik7YnJlYWt9Y2FzZSBtLlBvbHlEYXRhOntsZXQgcD1nLmRhdGEscz1PKGUscC5wb2ludHMsbiwwKSxJPU8oZSxwLnZlcnRpY2VzLG4sMSksZD1PKGUscC5saW5lcyxuLDIpLEU9TyhlLHAucG9seWdvbnMsbiwzKSxSPU8oZSxwLnRyaWFuZ2xlU3RyaXBzLG4sNCksdz1PKGUscC5wb2ludERhdGEsbiw1KSxrPU8oZSxwLnBvaW50RGF0YSxuLDYpLFdlPXtwb2x5RGF0YVR5cGU6cC5wb2x5RGF0YVR5cGUsbmFtZTpwLm5hbWUsbnVtYmVyT2ZQb2ludHM6cC5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWAsdmVydGljZXNCdWZmZXJTaXplOnAudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLGxpbmVzQnVmZmVyU2l6ZTpwLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2R9YCxwb2x5Z29uc0J1ZmZlclNpemU6cC5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOnAudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Un1gLG51bWJlck9mUG9pbnRQaXhlbHM6cC5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3d9YCxudW1iZXJPZkNlbGxQaXhlbHM6cC5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtrfWB9OyQoZSxXZSxuKTticmVha31jYXNlIFcuVGV4dDp7ZS5mc193cml0ZUZpbGUoZy5wYXRoLGcuZGF0YSk7YnJlYWt9Y2FzZSBXLkJpbmFyeTp7ZS5mc193cml0ZUZpbGUoZy5wYXRoLGcuZGF0YSk7YnJlYWt9Y2FzZSBXLkltYWdlOntsZXQgcD1nLmRhdGEscz17aW1hZ2VUeXBlOnAuaW1hZ2VUeXBlLG5hbWU6cC5uYW1lLG9yaWdpbjpwLm9yaWdpbixzcGFjaW5nOnAuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTpwLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKGUuZnNfbWtkaXJzKGAke2cucGF0aH0vZGF0YWApLGUuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkocykpLHAuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkocC5kYXRhLmJ1ZmZlcikpLGUuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShwLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFcuTWVzaDp7bGV0IHA9Zy5kYXRhLHM9e21lc2hUeXBlOnAubWVzaFR5cGUsbmFtZTpwLm5hbWUsbnVtYmVyT2ZQb2ludHM6cC5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczpwLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6cC5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOnAubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6cC5jZWxsQnVmZmVyU2l6ZX07aWYoZS5mc19ta2RpcnMoYCR7Zy5wYXRofS9kYXRhYCksZS5mc193cml0ZUZpbGUoYCR7Zy5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShzKSkscy5udW1iZXJPZlBvaW50cz4wKXtpZihwLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtlLmZzX3dyaXRlRmlsZShgJHtnLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkocC5wb2ludHMuYnVmZmVyKSl9aWYocy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKHAucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShwLnBvaW50RGF0YS5idWZmZXIpKX1pZihzLm51bWJlck9mQ2VsbHM+MCl7aWYocC5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KHAuY2VsbHMuYnVmZmVyKSl9aWYocy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYocC5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KHAuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLGUucmVzZXRNb2R1bGVTdGRvdXQoKSxlLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IGE9ZS5zdGFja1NhdmUoKSxvPTA7dHJ5e289ZS5jYWxsTWFpbihBLnNsaWNlKCkpfWNhdGNoKGcpe3Rocm93IHR5cGVvZiBnPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsZS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsZS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIGUuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsZS5nZXRFeGNlcHRpb25NZXNzYWdlKGcpKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLGd9ZmluYWxseXtlLnN0YWNrUmVzdG9yZShhKX1sZXQgaT1lLmdldE1vZHVsZVN0ZG91dCgpLGw9ZS5nZXRNb2R1bGVTdGRlcnIoKSxmPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZvPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKGcsbil7bGV0IHU9bnVsbDtzd2l0Y2goZy50eXBlKXtjYXNlIG0uVGV4dFN0cmVhbTp7bGV0IHM9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbiwwXSksST1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxuLDBdKSxkPW5ldyBVaW50OEFycmF5KGUuSEVBUFU4LmJ1ZmZlcixzLEkpO3U9e2RhdGE6bnIuZGVjb2RlKGQpfTticmVha31jYXNlIG0uSnNvbkNvbXBhdGlibGU6e2xldCBzPWUuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG4sMF0pLEk9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbiwwXSksZD1uZXcgVWludDhBcnJheShlLkhFQVBVOC5idWZmZXIscyxJKTt1PUpTT04ucGFyc2UobnIuZGVjb2RlKGQpKTticmVha31jYXNlIG0uQmluYXJ5U3RyZWFtOntsZXQgcz1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxuLDBdKSxJPWUuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG4sMF0pO3U9e2RhdGE6SXIoZSxzLEkpfTticmVha31jYXNlIG0uVGV4dEZpbGU6e3U9e3BhdGg6Zy5kYXRhLnBhdGgsZGF0YTplLmZzX3JlYWRGaWxlKGcuZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSBtLkJpbmFyeUZpbGU6e3U9e3BhdGg6Zy5kYXRhLnBhdGgsZGF0YTpIKGUsZy5kYXRhLnBhdGgpfTticmVha31jYXNlIG0uSW1hZ2U6e2xldCBzPXBBKGUsbik7cy5kYXRhPU4oZSxuLDAscy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSkscy5kaXJlY3Rpb249TihlLG4sMSxTLkZsb2F0NjQpLHMubWV0YWRhdGE9bmV3IE1hcChzLm1ldGFkYXRhKSx1PXM7YnJlYWt9Y2FzZSBtLk1lc2g6e2xldCBzPXBBKGUsbik7cy5udW1iZXJPZlBvaW50cz4wP3MucG9pbnRzPU4oZSxuLDAscy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOnMucG9pbnRzPUQocy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzLm51bWJlck9mQ2VsbHM+MD9zLmNlbGxzPU4oZSxuLDEscy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6cy5jZWxscz1EKHMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzLm51bWJlck9mUG9pbnRQaXhlbHM+MD9zLnBvaW50RGF0YT1OKGUsbiwyLHMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOnMucG9pbnREYXRhPUQocy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/cy5jZWxsRGF0YT1OKGUsbiwzLHMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6cy5jZWxsRGF0YT1EKHMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHU9czticmVha31jYXNlIG0uUG9seURhdGE6e2xldCBzPXBBKGUsbik7cy5udW1iZXJPZlBvaW50cz4wP3MucG9pbnRzPU4oZSxuLDAsUy5GbG9hdDMyKTpzLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LHMudmVydGljZXNCdWZmZXJTaXplPjA/cy52ZXJ0aWNlcz1OKGUsbiwxLFEuVUludDMyKTpzLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxzLmxpbmVzQnVmZmVyU2l6ZT4wP3MubGluZXM9TihlLG4sMixRLlVJbnQzMik6cy5saW5lcz1uZXcgVWludDMyQXJyYXkscy5wb2x5Z29uc0J1ZmZlclNpemU+MD9zLnBvbHlnb25zPU4oZSxuLDMsUS5VSW50MzIpOnMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LHMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/cy50cmlhbmdsZVN0cmlwcz1OKGUsbiw0LFEuVUludDMyKTpzLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxzLm51bWJlck9mUG9pbnRQaXhlbHM+MD9zLnBvaW50RGF0YT1OKGUsbiw1LHMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpzLnBvaW50RGF0YT1EKHMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSkscy5udW1iZXJPZkNlbGxQaXhlbHM+MD9zLmNlbGxEYXRhPU4oZSxuLDYscy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6cy5jZWxsRGF0YT1EKHMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSx1PXM7YnJlYWt9Y2FzZSBXLlRleHQ6e2lmKHR5cGVvZiBnLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTt1PWUuZnNfcmVhZEZpbGUoZy5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFcuQmluYXJ5OntpZih0eXBlb2YgZy5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7dT1IKGUsZy5wYXRoKTticmVha31jYXNlIFcuSW1hZ2U6e2lmKHR5cGVvZiBnLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgcz1lLmZzX3JlYWRGaWxlKGAke2cucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLEk9SlNPTi5wYXJzZShzKSxkPUgoZSxgJHtnLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtJLmRhdGE9RChJLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGQuYnVmZmVyKTtsZXQgRT1IKGUsYCR7Zy5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtJLmRpcmVjdGlvbj1EKFMuRmxvYXQ2NCxFLmJ1ZmZlciksdT1JO2JyZWFrfWNhc2UgVy5NZXNoOntpZih0eXBlb2YgZy5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IHM9ZS5mc19yZWFkRmlsZShgJHtnLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxJPUpTT04ucGFyc2Uocyk7aWYoSS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZD1IKGUsYCR7Zy5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtJLnBvaW50cz1EKEkubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkucG9pbnRzPUQoSS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihJLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGQ9SChlLGAke2cucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7SS5wb2ludERhdGE9RChJLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkucG9pbnREYXRhPUQoSS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKEkubnVtYmVyT2ZDZWxscz4wKXtsZXQgZD1IKGUsYCR7Zy5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO0kuY2VsbHM9RChJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkuY2VsbHM9RChJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoSS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGQ9SChlLGAke2cucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtJLmNlbGxEYXRhPUQoSS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkuY2VsbERhdGE9RChJLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTt1PUk7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgcD17dHlwZTpnLnR5cGUsZGF0YTp1fTtmLnB1c2gocCl9KSx7cmV0dXJuVmFsdWU6byxzdGRvdXQ6aSxzdGRlcnI6bCxvdXRwdXRzOmZ9fXZhciBscj1qaTt2YXIgbUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiBfaShlKXtsZXQgQT1lLHQ9ZTtpZih0eXBlb2YgZSE9InN0cmluZyImJihBPW5ldyBVUkwoZS5ocmVmKSx0PUEuaHJlZiksbUEuaGFzKHQpKXJldHVybiBtQS5nZXQodCk7e2xldCByPWF3YWl0IGlyKGUsdi5waXBlbGluZXNVcmwpO3JldHVybiBtQS5zZXQodCxyKSxyfX1hc3luYyBmdW5jdGlvbiB6aShlLEEsdCxyLGEsbyl7dmFyIGksbDtpZighYXdhaXQgYXIoKSl7bGV0IHc9IldlYkFzc2VtYmx5IFNJTUQgc3VwcG9ydCBpcyByZXF1aXJlZCAtLSBwbGVhc2UgdXBkYXRlIHlvdXIgYnJvd3Nlci4iO3Rocm93IGFsZXJ0KHcpLG5ldyBFcnJvcih3KX1pZihlPT09ITEpe2xldCB3PWF3YWl0IF9pKEEudG9TdHJpbmcoKSk7cmV0dXJuIGxyKHcsdCxyLGEpfWxldCBmPWUsZz0oaT1vPy5waXBlbGluZVdvcmtlclVybCkhPT1udWxsJiZpIT09dm9pZCAwP2k6bnVsbCxuPXR5cGVvZiBnIT0ic3RyaW5nIiYmdHlwZW9mIGc/LmhyZWY8InUiP2cuaHJlZjpnLHt3b3JrZXJQcm94eTp1LHdvcmtlcjpwfT1hd2FpdCBlcihmLG4pO2Y9cDtsZXQgcz1bXTthIT1udWxsJiZhLmxlbmd0aD4wJiZhLmZvckVhY2goZnVuY3Rpb24odyl7aWYody50eXBlPT09bS5CaW5hcnlTdHJlYW0pe2xldCBrPXcuZGF0YS5kYXRhO3MucHVzaChrKX1lbHNlIGlmKHcudHlwZT09PW0uQmluYXJ5RmlsZSl7bGV0IGs9dy5kYXRhLmRhdGE7cy5wdXNoKGspfWVsc2UgaWYody50eXBlPT09bS5JbWFnZSl7bGV0IGs9dy5kYXRhO2lmKGsuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlIGRhdGEgY2Fubm90IGJlIG51bGwiKTtzLnB1c2goLi4uZ0EoaykpfWVsc2UgaWYody50eXBlPT09Vy5CaW5hcnkpcy5wdXNoKHcuZGF0YSk7ZWxzZSBpZih3LnR5cGU9PT1XLkltYWdlKXtsZXQgaz13LmRhdGE7aWYoay5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UgZGF0YSBjYW5ub3QgYmUgbnVsbCIpO3MucHVzaCguLi5nQShrKSl9ZWxzZSBpZih3LnR5cGU9PT1XLk1lc2gpe2xldCBrPXcuZGF0YTtzLnB1c2goLi4ucnIoaykpfX0pO2xldCBJPShsPW8/LnBpcGVsaW5lQmFzZVVybCkhPT1udWxsJiZsIT09dm9pZCAwP2w6InBpcGVsaW5lc1VybCIsZD10eXBlb2YgSSE9InN0cmluZyImJnR5cGVvZiBJPy5ocmVmPCJ1Ij9JLmhyZWY6SSxFPWEhPW51bGw/bEEoYSxsdChzKSk6bnVsbCxSPWF3YWl0IHUucnVuUGlwZWxpbmUodixBLnRvU3RyaW5nKCksZCx0LHIsRSk7cmV0dXJue3JldHVyblZhbHVlOlIucmV0dXJuVmFsdWUsc3Rkb3V0OlIuc3Rkb3V0LHN0ZGVycjpSLnN0ZGVycixvdXRwdXRzOlIub3V0cHV0cyx3ZWJXb3JrZXI6Zn19dmFyIEI9emk7dmFyIGdyPXtuYW1lOiJAaXRrLXdhc20vaW1hZ2UtaW8iLHZlcnNpb246IjAuNC4wIixkZXNjcmlwdGlvbjoiSW5wdXQgYW5kIG91dHB1dCBmb3Igc2NpZW50aWZpYyBhbmQgbWVkaWNhbCBpbWFnZSBmaWxlIGZvcm1hdHMuIix0eXBlOiJtb2R1bGUiLG1vZHVsZToiLi9kaXN0L2luZGV4LmpzIix0eXBlczoiLi9kaXN0L2luZGV4LmQudHMiLGV4cG9ydHM6eyIuIjp7dHlwZXM6Ii4vZGlzdC9pbmRleC5kLmpzIixicm93c2VyOiIuL2Rpc3QvaW5kZXguanMiLG5vZGU6Ii4vZGlzdC9pbmRleC1ub2RlLmpzIixkZWZhdWx0OiIuL2Rpc3QvaW5kZXguanMifX0sc2NyaXB0czp7c3RhcnQ6Im5wbSBydW4gY29weVNob2VsYWNlQXNzZXRzICYmIHZpdGUgLWMgYnVpbGQvdml0ZS5jb25maWcuanMiLHRlc3Q6Im5wbSBydW4gdGVzdDpub2RlICYmIG5wbSBydW4gdGVzdDpicm93c2VyIiwidGVzdDpub2RlIjoiYXZhIiwidGVzdDpicm93c2VyIjoibnBtIHJ1biB0ZXN0OmJyb3dzZXI6Y2hyb21lICYmIG5wbSBydW4gdGVzdDpicm93c2VyOmZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6ZmlyZWZveCI6InN0YXJ0LXNlcnZlci1hbmQtdGVzdCByb2xsdXA6c3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTAwNCBjeXByZXNzOnJ1bkZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6Y2hyb21lIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHJvbGx1cDpzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MDA0IGN5cHJlc3M6cnVuQ2hyb21lIiwidGVzdDpicm93c2VyOmRlYnVnIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHJvbGx1cDpzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MDA0IGN5cHJlc3M6b3BlbiIsImN5cHJlc3M6b3BlbiI6Im5weCBjeXByZXNzIG9wZW4iLCJjeXByZXNzOnJ1bkNocm9tZSI6Im5weCBjeXByZXNzIHJ1biAtLWJyb3dzZXIgY2hyb21lIiwiY3lwcmVzczpydW5GaXJlZm94IjoibnB4IGN5cHJlc3MgcnVuIC0tYnJvd3NlciBmaXJlZm94IixidWlsZDoibnBtIHJ1biBidWlsZDp0c2MgJiYgbnBtIHJ1biBidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkICYmIG5wbSBydW4gYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZE1pbiAmJiBucG0gcnVuIGJ1aWxkOmRlbW8iLCJidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkIjoiZXNidWlsZCAtLWxvYWRlcjoud29ya2VyLmpzPWRhdGF1cmwgLS1idW5kbGUgLS1mb3JtYXQ9ZXNtIC0tb3V0ZmlsZT0uL2Rpc3QvaW1hZ2UtaW8td29ya2VyLWVtYmVkZGVkLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC50cyIsImJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWRNaW4iOiJlc2J1aWxkIC0tbWluaWZ5IC0tbG9hZGVyOi53b3JrZXIuanM9ZGF0YXVybCAtLWJ1bmRsZSAtLWZvcm1hdD1lc20gLS1vdXRmaWxlPS4vZGlzdC9pbWFnZS1pby13b3JrZXItZW1iZWRkZWQubWluLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC1taW4udHMiLCJidWlsZDp0c2MiOiJ0c2MgLS1wcmV0dHkiLGNvcHlTaG9lbGFjZUFzc2V0czoic2h4IG1rZGlyIC1wIHRlc3QvYnJvd3Nlci9kZW1vLWFwcC9wdWJsaWMgJiYgc2h4IGNwIC1yIG5vZGVfbW9kdWxlcy9Ac2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UvZGlzdC9hc3NldHMgdGVzdC9icm93c2VyL2RlbW8tYXBwL3B1YmxpYy8iLCJidWlsZDpkZW1vIjoibnBtIHJ1biBjb3B5U2hvZWxhY2VBc3NldHMgJiYgdml0ZSAtYyBidWlsZC92aXRlLmNvbmZpZy5qcyBidWlsZCIsInJvbGx1cDpzdGFydCI6Im5wbSBydW4gY29weVNob2VsYWNlQXNzZXRzICYmIGNvbmN1cnJlbnRseSBucG06cm9sbHVwOmRldiBucG06cm9sbHVwOnByZXZpZXciLCJyb2xsdXA6ZGV2Ijoidml0ZSBidWlsZCAtLWNvbmZpZyBidWlsZC92aXRlLXJvbGx1cC13YXRjaC5jb25maWcudHMiLCJyb2xsdXA6cHJldmlldyI6InZpdGUgcHJldmlldyAtLWNvbmZpZyBidWlsZC92aXRlLXJvbGx1cC13YXRjaC5jb25maWcudHMifSxrZXl3b3JkczpbIml0ayIsIndhc20iLCJ3ZWJhc3NlbWJseSIsIndhc2kiXSxhdXRob3I6IiIsbGljZW5zZToiQXBhY2hlLTIuMCIsZGVwZW5kZW5jaWVzOnsiaXRrLXdhc20iOiJeMS4wLjAtYi4xNTQifSxkZXZEZXBlbmRlbmNpZXM6eyJAc2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UiOiJeMi41LjIiLCJAdHlwZXMvbm9kZSI6Il4yMC4yLjUiLGF2YToiXjUuMy4xIixjb25jdXJyZW50bHk6Il44LjIuMSIsY3lwcmVzczoiXjEzLjMuMCIsZXNidWlsZDoiXjAuMTkuNSIsc2h4OiJeMC4zLjQiLCJzdGFydC1zZXJ2ZXItYW5kLXRlc3QiOiJeMi4wLjEiLHR5cGVzY3JpcHQ6Il41LjAuNCIsdml0ZToiXjQuNS4wIiwidml0ZS1wbHVnaW4tc3RhdGljLWNvcHkiOiJeMC4xNy4wIn0scmVwb3NpdG9yeTp7dHlwZToiZ2l0Iix1cmw6Imh0dHBzOi8vZ2l0aHViLmNvbS9JbnNpZ2h0U29mdHdhcmVDb25zb3J0aXVtL2l0ay13YXNtIn0sYXZhOntmaWxlczpbInRlc3Qvbm9kZS8qKi8qIiwiIXRlc3Qvbm9kZS9jb21tb24uanMiXX19O3ZhciB1QSxaaT1gaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AaXRrLXdhc20vaW1hZ2UtaW9AJHtnci52ZXJzaW9ufS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gcGwoZSl7dUE9ZX1mdW5jdGlvbiBDKCl7aWYodHlwZW9mIHVBPCJ1IilyZXR1cm4gdUE7bGV0IGU9dHIoKTtyZXR1cm4gdHlwZW9mIGU8InUiP2U6Wml9dmFyIGZBLFhpPW51bGw7ZnVuY3Rpb24gcHIoZSl7ZkE9ZX1mdW5jdGlvbiB5KCl7aWYodHlwZW9mIGZBPCJ1IilyZXR1cm4gZkE7bGV0IGU9QXIoKTtyZXR1cm4gdHlwZW9mIGU8InUiP2U6WGl9dmFyICRpPW5ldyBNYXAoW1siaW1hZ2UvanBlZyIsImpwZWciXSxbImltYWdlL3BuZyIsInBuZyJdLFsiaW1hZ2UvdGlmZiIsInRpZmYiXSxbImltYWdlL3gtbXMtYm1wIiwiYm1wIl0sWyJpbWFnZS94LWJtcCIsImJtcCJdLFsiaW1hZ2UvYm1wIiwiYm1wIl0sWyJhcHBsaWNhdGlvbi9kaWNvbSIsImdkY20iXV0pLGVlPSRpO3ZhciBlYT1uZXcgTWFwKFtbImJtcCIsImJtcCJdLFsiZGNtIiwiZ2RjbSJdLFsiZ2lwbCIsImdpcGwiXSxbImdpcGwuZ3oiLCJnaXBsIl0sWyJoZGY1IiwiaGRmNSJdLFsianBnIiwianBlZyJdLFsianBlZyIsImpwZWciXSxbIml3aSIsIndhc20iXSxbIml3aS5jYm9yIiwid2FzbSJdLFsiaXdpLmNib3IuenN0Iiwid2FzbVpzdGQiXSxbImxzbSIsImxzbSJdLFsibW5jIiwibW5jIl0sWyJtbmMuZ3oiLCJtbmMiXSxbIm1uYzIiLCJtbmMiXSxbIm1naCIsIm1naCJdLFsibWd6IiwibWdoIl0sWyJtZ2guZ3oiLCJtZ2giXSxbIm1oYSIsIm1ldGEiXSxbIm1oZCIsIm1ldGEiXSxbIm1yYyIsIm1yYyJdLFsibmlhIiwibmlmdGkiXSxbIm5paSIsIm5pZnRpIl0sWyJuaWkuZ3oiLCJuaWZ0aSJdLFsiaGRyIiwibmlmdGkiXSxbIm5ycmQiLCJucnJkIl0sWyJuaGRyIiwibnJyZCJdLFsicG5nIiwicG5nIl0sWyJwaWMiLCJiaW9SYWQiXSxbInRpZiIsInRpZmYiXSxbInRpZmYiLCJ0aWZmIl0sWyJ2dGsiLCJ2dGsiXSxbImlzcSIsInNjYW5jbyJdLFsiYWltIiwic2NhbmNvIl0sWyJmZGYiLCJmZGYiXV0pLEFlPWVhO2FzeW5jIGZ1bmN0aW9uIEFhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0icG5nLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBjQT1BYTthc3luYyBmdW5jdGlvbiB0YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InBuZy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgZEE9dGE7YXN5bmMgZnVuY3Rpb24gcmEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJtZXRhLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBCQT1yYTthc3luYyBmdW5jdGlvbiBpYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1ldGEtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIENBPWlhO2FzeW5jIGZ1bmN0aW9uIGFhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0idGlmZi1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgeUE9YWE7YXN5bmMgZnVuY3Rpb24gb2EoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ0aWZmLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBFQT1vYTthc3luYyBmdW5jdGlvbiBuYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Im5pZnRpLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBRQT1uYTthc3luYyBmdW5jdGlvbiBzYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im5pZnRpLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBoQT1zYTthc3luYyBmdW5jdGlvbiBJYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImpwZWctcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHdBPUlhO2FzeW5jIGZ1bmN0aW9uIGxhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0ianBlZy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgUkE9bGE7YXN5bmMgZnVuY3Rpb24gZ2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJucnJkLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBiQT1nYTthc3luYyBmdW5jdGlvbiBwYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im5ycmQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIGtBPXBhO2FzeW5jIGZ1bmN0aW9uIG1hKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0idnRrLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBEQT1tYTthc3luYyBmdW5jdGlvbiB1YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InZ0ay13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgRkE9dWE7YXN5bmMgZnVuY3Rpb24gZmEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJibXAtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIE9BPWZhO2FzeW5jIGZ1bmN0aW9uIGNhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iYm1wLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBVQT1jYTthc3luYyBmdW5jdGlvbiBkYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImhkZjUtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIFNBPWRhO2FzeW5jIGZ1bmN0aW9uIEJhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iaGRmNS13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgV0E9QmE7YXN5bmMgZnVuY3Rpb24gQ2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJtaW5jLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBOQT1DYTthc3luYyBmdW5jdGlvbiB5YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1pbmMtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIFBBPXlhO2FzeW5jIGZ1bmN0aW9uIEVhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0ibXJjLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciB4QT1FYTthc3luYyBmdW5jdGlvbiBRYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1yYy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgR0E9UWE7YXN5bmMgZnVuY3Rpb24gaGEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJsc20tcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIFRBPWhhO2FzeW5jIGZ1bmN0aW9uIHdhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0ibHNtLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBKQT13YTthc3luYyBmdW5jdGlvbiBSYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Im1naC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgTEE9UmE7YXN5bmMgZnVuY3Rpb24gYmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJtZ2gtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIE1BPWJhO2FzeW5jIGZ1bmN0aW9uIGthKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0iYmlvLXJhZC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgSEE9a2E7YXN5bmMgZnVuY3Rpb24gRGEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJiaW8tcmFkLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBZQT1EYTthc3luYyBmdW5jdGlvbiBGYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImdpcGwtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHFBPUZhO2FzeW5jIGZ1bmN0aW9uIE9hKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iZ2lwbC13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgdkE9T2E7YXN5bmMgZnVuY3Rpb24gVWEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJnZS1hZHctcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIEtBPVVhO2FzeW5jIGZ1bmN0aW9uIFNhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iZ2UtYWR3LXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBqQT1TYTthc3luYyBmdW5jdGlvbiBXYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImdlNC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgX0E9V2E7YXN5bmMgZnVuY3Rpb24gTmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJnZTQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIHpBPU5hO2FzeW5jIGZ1bmN0aW9uIFBhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0iZ2U1LXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBWQT1QYTthc3luYyBmdW5jdGlvbiB4YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49ImdlNS13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgWkE9eGE7YXN5bmMgZnVuY3Rpb24gR2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJnZGNtLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBYQT1HYTthc3luYyBmdW5jdGlvbiBUYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49ImdkY20td3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyICRBPVRhO2FzeW5jIGZ1bmN0aW9uIEphKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0ic2NhbmNvLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBldD1KYTthc3luYyBmdW5jdGlvbiBMYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InNjYW5jby13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgQXQ9TGE7YXN5bmMgZnVuY3Rpb24gTWEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJmZGYtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHR0PU1hO2FzeW5jIGZ1bmN0aW9uIEhhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0id2FzbS1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgcnQ9SGE7YXN5bmMgZnVuY3Rpb24gWWEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ3YXNtLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBpdD1ZYTthc3luYyBmdW5jdGlvbiBxYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Indhc20tenN0ZC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgYXQ9cWE7YXN5bmMgZnVuY3Rpb24gdmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ3YXNtLXpzdGQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIG90PXZhO3ZhciBLYT1uZXcgTWFwKFtbInBuZyIsW2NBLGRBXV0sWyJtZXRhIixbQkEsQ0FdXSxbInRpZmYiLFt5QSxFQV1dLFsibmlmdGkiLFtRQSxoQV1dLFsianBlZyIsW3dBLFJBXV0sWyJucnJkIixbYkEsa0FdXSxbInZ0ayIsW0RBLEZBXV0sWyJibXAiLFtPQSxVQV1dLFsiaGRmNSIsW1NBLFdBXV0sWyJtaW5jIixbTkEsUEFdXSxbIm1yYyIsW3hBLEdBXV0sWyJsc20iLFtUQSxKQV1dLFsibWdoIixbTEEsTUFdXSxbImJpb1JhZCIsW0hBLFlBXV0sWyJnaXBsIixbcUEsdkFdXSxbImdlQWR3IixbS0EsakFdXSxbImdlNCIsW19BLHpBXV0sWyJnZTUiLFtWQSxaQV1dLFsiZ2RjbSIsW1hBLCRBXV0sWyJzY2FuY28iLFtldCxBdF1dLFsiZmRmIixbdHQsbnVsbF1dLFsid2FzbSIsW3J0LGl0XV0sWyJ3YXNtWnN0ZCIsW2F0LG90XV1dKSx0ZT1LYTthc3luYyBmdW5jdGlvbiBqYShlLEEsdD17fSl7bGV0IHI9QS50eXBlPz8iIixhPUEubmFtZT8/QS5wYXRoPz8iZmlsZU5hbWUiLG89bWUoYSkudG9Mb3dlckNhc2UoKSxpPWUsbD1BO2lmKEEgaW5zdGFuY2VvZiBCbG9iKXtsZXQgST1hd2FpdCBBLmFycmF5QnVmZmVyKCk7bD17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShJKX19bGV0IGY9bnVsbDtpZihyJiZlZS5oYXMocikpZj1lZS5nZXQocik7ZWxzZSBpZihBZS5oYXMobykpZj1BZS5nZXQobyk7ZWxzZSBmb3IobGV0IEkgb2YgdGUudmFsdWVzKCkpaWYoSVswXSE9PW51bGwpe2xldHt3ZWJXb3JrZXI6ZCxjb3VsZFJlYWQ6RSxpbWFnZTpSfT1hd2FpdCBJWzBdKGkse3BhdGg6bC5wYXRoLGRhdGE6bC5kYXRhLnNsaWNlKCl9LHtpbmZvcm1hdGlvbk9ubHk6dC5pbmZvcm1hdGlvbk9ubHl9KTtpZihpPWQsRSlyZXR1cm4gdHlwZW9mIHQ8InUiJiYoUj1UKFIsdCkpLHt3ZWJXb3JrZXI6aSxpbWFnZTpSfX1pZighZil0aHJvdyBFcnJvcigiQ291bGQgbm90IGZpbmQgSU8gZm9yOiAiK2EpO2xldCBuPXRlLmdldChmKVswXSx7d2ViV29ya2VyOnUsY291bGRSZWFkOnAsaW1hZ2U6c309YXdhaXQgbihpLGwse2luZm9ybWF0aW9uT25seTp0LmluZm9ybWF0aW9uT25seX0pO2lmKGk9dSwhcCl0aHJvdyBFcnJvcigiQ291bGQgbm90IHJlYWQ6ICIrYSk7cmV0dXJuIHR5cGVvZiB0PCJ1IiYmKHM9VChzLHQpKSx7d2ViV29ya2VyOmksaW1hZ2U6c319dmFyIG50PWphO3ZhciBfYT10eXBlb2YgZ2xvYmFsVGhpcy5uYXZpZ2F0b3I/LmhhcmR3YXJlQ29uY3VycmVuY3k9PSJudW1iZXIiP2dsb2JhbFRoaXMubmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3k6Nixtcj1uZXcgSmUoX2EsbnQpO2FzeW5jIGZ1bmN0aW9uIHphKGUsQSl7bGV0IHQ9MSxyPTAsYT0hMTt0eXBlb2YgQT09Im9iamVjdCImJih0eXBlb2YgQS56U3BhY2luZzwidSImJih0PUEuelNwYWNpbmcpLHR5cGVvZiBBLnpPcmlnaW48InUiJiYocj1BLnpPcmlnaW4pLHR5cGVvZiBBLnNvcnRlZFNlcmllczwidSImJihhPUEuc29ydGVkU2VyaWVzKSk7bGV0IG89QXJyYXkuZnJvbShlLGFzeW5jIGZ1bmN0aW9uKHUpe3JldHVybiBhd2FpdCB1LmFycmF5QnVmZmVyKCkudGhlbihmdW5jdGlvbihwKXtyZXR1cm57bmFtZTp1Lm5hbWUsdHlwZTp1LnR5cGUsZGF0YTpwfX0pfSksaT1hd2FpdCBQcm9taXNlLmFsbChvKTthfHxpLnNvcnQoKHUscCk9PnUubmFtZTxwLm5hbWU/LTE6dS5uYW1lPnAubmFtZT8xOjApO2xldCBsPVtdO2ZvcihsZXQgdT0wO3U8aS5sZW5ndGg7dSsrKWwucHVzaChbaVt1XS5kYXRhLGlbdV0ubmFtZV0pO2xldCBnPShhd2FpdCBtci5ydW5UYXNrcyhsKS5wcm9taXNlKS5tYXAodT0+e2xldCBwPXUuaW1hZ2U7cmV0dXJuIHAuaW1hZ2VUeXBlLmRpbWVuc2lvbj0zLHAuc2l6ZS5wdXNoKDEpLHAuc3BhY2luZy5wdXNoKHQpLHAub3JpZ2luLnB1c2gocikscC5kaXJlY3Rpb249bmV3IEZsb2F0NjRBcnJheSg5KSxwLmRpcmVjdGlvbi5maWxsKDApLHAuZGlyZWN0aW9uWzBdPTEscC5kaXJlY3Rpb25bNF09MSxwLmRpcmVjdGlvbls4XT0xLHB9KSxuPUdlKGcpO3JldHVybiB0eXBlb2YgQT09Im9iamVjdCImJih0eXBlb2YgQS5jb21wb25lbnRUeXBlPCJ1Inx8dHlwZW9mIEEucGl4ZWxUeXBlPCJ1IikmJihuPVQobixBKSkse2ltYWdlOm4sd2ViV29ya2VyUG9vbDptcn19dmFyIFZhPXphO2FzeW5jIGZ1bmN0aW9uIFphKGUsQSx0LHI9e30pe2xldCBhPUE7KHR5cGVvZiByLmNvbXBvbmVudFR5cGU8InUifHx0eXBlb2Ygci5waXhlbFR5cGU8InUiKSYmKGE9VChBLHIpKTtsZXQgbz1yLm1pbWVUeXBlLGk9bWUodCkudG9Mb3dlckNhc2UoKSxsPWUsZj1udWxsO2lmKHR5cGVvZiBvPCJ1IiYmZWUuaGFzKG8pKWY9ZWUuZ2V0KG8pO2Vsc2UgaWYoQWUuaGFzKGkpKWY9QWUuZ2V0KGkpO2Vsc2UgZm9yKGxldCBkIG9mIHRlLnZhbHVlcygpKWlmKGRbMV0hPT1udWxsKXtsZXR7d2ViV29ya2VyOkUsY291bGRXcml0ZTpSLHNlcmlhbGl6ZWRJbWFnZTp3fT1hd2FpdCBkWzFdKGwseGUoYSksdCxyKTtpZihsPUUsUilyZXR1cm57d2ViV29ya2VyOmwsc2VyaWFsaXplZEltYWdlOnd9fWlmKCFmKXRocm93IEVycm9yKCJDb3VsZCBub3QgZmluZCBJTyBmb3I6ICIrdCk7bGV0IG49dGUuZ2V0KGYpWzFdLHt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOnAsc2VyaWFsaXplZEltYWdlOnN9PWF3YWl0IG4obCxhLHQscik7aWYobD11LCFwKXRocm93IEVycm9yKCJDb3VsZCBub3Qgd3JpdGU6ICIrdCk7cmV0dXJue3dlYldvcmtlcjpsLHNlcmlhbGl6ZWRJbWFnZTpzfX12YXIgWGE9WmE7YXN5bmMgZnVuY3Rpb24gJGEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJmZGYtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIGVvPSRhO3ZhciB1cj0nZGF0YTp0ZXh0L2phdmFzY3JpcHQ7Y2hhcnNldD11dGYtOCx2YXIgY2U9U3ltYm9sKCJDb21saW5rLnByb3h5IiksQ3Q9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IiksQnQ9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLE1BPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksZmU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsUXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmQVtjZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gRUEoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLGx0KEEpfX0sRXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LGxlPW5ldyBNYXAoW1sicHJveHkiLFF0XSxbInRocm93IixFdF1dKTtmdW5jdGlvbiBjdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gRUEoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBJKHIpe2lmKCFyfHwhci5kYXRhKXJldHVybjtpZighY3QodCxyLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gXCcke3Iub3JpZ2lufVwnIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6ZyxwYXRoOm59PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksRT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChxKSxvO3RyeXtsZXQgQj1uLnNsaWNlKDAsLTEpLnJlZHVjZSgoYSxDKT0+YVtDXSxBKSxjPW4ucmVkdWNlKChhLEMpPT5hW0NdLEEpO3N3aXRjaChnKXtjYXNlIkdFVCI6bz1jO2JyZWFrO2Nhc2UiU0VUIjpCW24uc2xpY2UoLTEpWzBdXT1xKHIuZGF0YS52YWx1ZSksbz0hMDticmVhaztjYXNlIkFQUExZIjpvPWMuYXBwbHkoQixFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBhPW5ldyBjKC4uLkUpO289bXQoYSl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTphLHBvcnQyOkN9PW5ldyBNZXNzYWdlQ2hhbm5lbDtFQShBLEMpLG89SEEoYSxbYV0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6bz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKEIpe289e3ZhbHVlOkIsW3NBXTowfX1Qcm9taXNlLnJlc29sdmUobykuY2F0Y2goQj0+KHt2YWx1ZTpCLFtzQV06MH0pKS50aGVuKEI9PntsZXRbYyxhXT1RQShCKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLGEpLGc9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLHVlKGUpLE1BIGluIEEmJnR5cGVvZiBBW01BXT09ImZ1bmN0aW9uIiYmQVtNQV0oKSl9KS5jYXRjaChCPT57bGV0W2MsYV09UUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtzQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LGMpLHtpZDppfSksYSl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBmdChBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiB1ZShBKXtmdChBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGx0KEEsZSl7cmV0dXJuIGJBKEEsW10sZSl9ZnVuY3Rpb24gYUEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIGhlKEEpe3JldHVybiB4KEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e3VlKEEpfSl9dmFyIENBPW5ldyBXZWFrTWFwLEJBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPShDQS5nZXQoQSl8fDApLTE7Q0Euc2V0KEEsZSksZT09PTAmJmhlKEEpfSk7ZnVuY3Rpb24gdXQoQSxlKXtsZXQgdD0oQ0EuZ2V0KGUpfHwwKSsxO0NBLnNldChlLHQpLEJBJiZCQS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gaHQoQSl7QkEmJkJBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gYkEoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgST0hMSxyPW5ldyBQcm94eSh0LHtnZXQoaSxnKXtpZihhQShJKSxnPT09QnQpcmV0dXJuKCk9PntodChyKSxoZShBKSxJPSEwfTtpZihnPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9PnJ9O2xldCBuPXgoQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKEU9PkUudG9TdHJpbmcoKSl9KS50aGVuKHEpO3JldHVybiBuLnRoZW4uYmluZChuKX1yZXR1cm4gYkEoQSxbLi4uZSxnXSl9LHNldChpLGcsbil7YUEoSSk7bGV0W0Usb109UUEobik7cmV0dXJuIHgoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGddLm1hcChCPT5CLnRvU3RyaW5nKCkpLHZhbHVlOkV9LG8pLnRoZW4ocSl9LGFwcGx5KGksZyxuKXthQShJKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1DdClyZXR1cm4geChBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKHEpO2lmKEU9PT0iYmluZCIpcmV0dXJuIGJBKEEsZS5zbGljZSgwLC0xKSk7bGV0W28sQl09RWUobik7cmV0dXJuIHgoQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoYz0+Yy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6b30sQikudGhlbihxKX0sY29uc3RydWN0KGksZyl7YUEoSSk7bGV0W24sRV09RWUoZyk7cmV0dXJuIHgoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKG89Pm8udG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Om59LEUpLnRoZW4ocSl9fSk7cmV0dXJuIHV0KHIsQSkscn1mdW5jdGlvbiBkdChBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBFZShBKXtsZXQgZT1BLm1hcChRQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGR0KGUubWFwKHQ9PnRbMV0pKV19dmFyIGRlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIEhBKEEsZSl7cmV0dXJuIGRlLnNldChBLGUpLEF9ZnVuY3Rpb24gbXQoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W2NlXTohMH0pfWZ1bmN0aW9uIFFBKEEpe2ZvcihsZXRbZSx0XW9mIGxlKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZGUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gcShBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBsZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIHgoQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShJPT57bGV0IHI9RHQoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkoZyl7IWcuZGF0YXx8IWcuZGF0YS5pZHx8Zy5kYXRhLmlkIT09cnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSksSShnLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOnJ9LGUpLHQpfSl9ZnVuY3Rpb24gRHQoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIFgoQSxlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShlLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzp5dH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6VEF9PU9iamVjdCxmQT0oQT0+ZT0+e2xldCB0PXl0LmNhbGwoZSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxVPUE9PihBPUEudG9Mb3dlckNhc2UoKSxlPT5mQShlKT09PUEpLGxBPUE9PmU9PnR5cGVvZiBlPT09QSx7aXNBcnJheTpQfT1BcnJheSx2PWxBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiB3dChBKXtyZXR1cm4gQSE9PW51bGwmJiF2KEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIXYoQS5jb25zdHJ1Y3RvcikmJlIoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIHdlPVUoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gcHQoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZ3ZShBLmJ1ZmZlciksZX12YXIgRnQ9bEEoInN0cmluZyIpLFI9bEEoImZ1bmN0aW9uIikscGU9bEEoIm51bWJlciIpLHVBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsU3Q9QT0+QT09PSEwfHxBPT09ITEsY0E9QT0+e2lmKGZBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9VEEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sTnQ9VSgiRGF0ZSIpLFJ0PVUoIkZpbGUiKSxHdD1VKCJCbG9iIiksVXQ9VSgiRmlsZUxpc3QiKSxrdD1BPT51QShBKSYmUihBLnBpcGUpLEx0PUE9PntsZXQgZTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxSKEEuYXBwZW5kKSYmKChlPWZBKEEpKT09PSJmb3JtZGF0YSJ8fGU9PT0ib2JqZWN0IiYmUihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxPdD1VKCJVUkxTZWFyY2hQYXJhbXMiKSxKdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gJChBLGUse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBJLHI7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLFAoQSkpZm9yKEk9MCxyPUEubGVuZ3RoO0k8cjtJKyspZS5jYWxsKG51bGwsQVtJXSxJLEEpO2Vsc2V7bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxnPWkubGVuZ3RoLG47Zm9yKEk9MDtJPGc7SSsrKW49aVtJXSxlLmNhbGwobnVsbCxBW25dLG4sQSl9fWZ1bmN0aW9uIEZlKEEsZSl7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgU2U9KCgpPT50eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsKSgpLE5lPUE9PiF2KEEpJiZBIT09U2U7ZnVuY3Rpb24gcUEoKXtsZXR7Y2FzZWxlc3M6QX09TmUodGhpcykmJnRoaXN8fHt9LGU9e30sdD0oSSxyKT0+e2xldCBpPUEmJkZlKGUscil8fHI7Y0EoZVtpXSkmJmNBKEkpP2VbaV09cUEoZVtpXSxJKTpjQShJKT9lW2ldPXFBKHt9LEkpOlAoSSk/ZVtpXT1JLnNsaWNlKCk6ZVtpXT1JfTtmb3IobGV0IEk9MCxyPWFyZ3VtZW50cy5sZW5ndGg7STxyO0krKylhcmd1bWVudHNbSV0mJiQoYXJndW1lbnRzW0ldLHQpO3JldHVybiBlfXZhciBNdD0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4oJChlLChyLGkpPT57dCYmUihyKT9BW2ldPVgocix0KTpBW2ldPXJ9LHthbGxPd25LZXlzOkl9KSxBKSxidD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLEh0PShBLGUsdCxJKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZS5wcm90b3R5cGUsSSksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTplLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LFl0PShBLGUsdCxJKT0+e2xldCByLGksZyxuPXt9O2lmKGU9ZXx8e30sQT09bnVsbClyZXR1cm4gZTtkb3tmb3Iocj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxpPXIubGVuZ3RoO2ktLSA+MDspZz1yW2ldLCghSXx8SShnLEEsZSkpJiYhbltnXSYmKGVbZ109QVtnXSxuW2ddPSEwKTtBPXQhPT0hMSYmVEEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsZSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIGV9LHF0PShBLGUsdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1lLmxlbmd0aDtsZXQgST1BLmluZGV4T2YoZSx0KTtyZXR1cm4gSSE9PS0xJiZJPT09dH0sVHQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKFAoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIXBlKGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxLdD0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmVEEoVWludDhBcnJheSkpLHh0PShBLGUpPT57bGV0IEk9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxyO2Zvcig7KHI9SS5uZXh0KCkpJiYhci5kb25lOyl7bGV0IGk9ci52YWx1ZTtlLmNhbGwoQSxpWzBdLGlbMV0pfX0sUHQ9KEEsZSk9PntsZXQgdCxJPVtdO2Zvcig7KHQ9QS5leGVjKGUpKSE9PW51bGw7KUkucHVzaCh0KTtyZXR1cm4gSX0sV3Q9VSgiSFRNTEZvcm1FbGVtZW50IiksanQ9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24odCxJLHIpe3JldHVybiBJLnRvVXBwZXJDYXNlKCkrcn0pLERlPSgoe2hhc093blByb3BlcnR5OkF9KT0+KGUsdCk9PkEuY2FsbChlLHQpKShPYmplY3QucHJvdG90eXBlKSxadD1VKCJSZWdFeHAiKSxSZT0oQSxlKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLEk9e307JCh0LChyLGkpPT57ZShyLGksQSkhPT0hMSYmKElbaV09cil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLEkpfSxfdD1BPT57UmUoQSwoZSx0KT0+e2lmKFIoQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCBJPUFbdF07aWYoUihJKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kIFwnIit0KyJcJyIpfSl9fSl9LFZ0PShBLGUpPT57bGV0IHQ9e30sST1yPT57ci5mb3JFYWNoKGk9Pnt0W2ldPSEwfSl9O3JldHVybiBQKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LHp0PSgpPT57fSxYdD0oQSxlKT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6ZSksWUE9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iix5ZT0iMDEyMzQ1Njc4OSIsR2U9e0RJR0lUOnllLEFMUEhBOllBLEFMUEhBX0RJR0lUOllBK1lBLnRvVXBwZXJDYXNlKCkreWV9LHZ0PShBPTE2LGU9R2UuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpJfT1lO2Zvcig7QS0tOyl0Kz1lW01hdGgucmFuZG9tKCkqSXwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gJHQoQSl7cmV0dXJuISEoQSYmUihBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIEFJPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZih1QShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1QKEkpP1tdOnt9O3JldHVybiAkKEksKGcsbik9PntsZXQgRT10KGcscisxKTshdihFKSYmKGlbbl09RSl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sZUk9VSgiQXN5bmNGdW5jdGlvbiIpLHRJPUE9PkEmJih1QShBKXx8UihBKSkmJlIoQS50aGVuKSYmUihBLmNhdGNoKSxzPXtpc0FycmF5OlAsaXNBcnJheUJ1ZmZlcjp3ZSxpc0J1ZmZlcjp3dCxpc0Zvcm1EYXRhOkx0LGlzQXJyYXlCdWZmZXJWaWV3OnB0LGlzU3RyaW5nOkZ0LGlzTnVtYmVyOnBlLGlzQm9vbGVhbjpTdCxpc09iamVjdDp1QSxpc1BsYWluT2JqZWN0OmNBLGlzVW5kZWZpbmVkOnYsaXNEYXRlOk50LGlzRmlsZTpSdCxpc0Jsb2I6R3QsaXNSZWdFeHA6WnQsaXNGdW5jdGlvbjpSLGlzU3RyZWFtOmt0LGlzVVJMU2VhcmNoUGFyYW1zOk90LGlzVHlwZWRBcnJheTpLdCxpc0ZpbGVMaXN0OlV0LGZvckVhY2g6JCxtZXJnZTpxQSxleHRlbmQ6TXQsdHJpbTpKdCxzdHJpcEJPTTpidCxpbmhlcml0czpIdCx0b0ZsYXRPYmplY3Q6WXQsa2luZE9mOmZBLGtpbmRPZlRlc3Q6VSxlbmRzV2l0aDpxdCx0b0FycmF5OlR0LGZvckVhY2hFbnRyeTp4dCxtYXRjaEFsbDpQdCxpc0hUTUxGb3JtOld0LGhhc093blByb3BlcnR5OkRlLGhhc093blByb3A6RGUscmVkdWNlRGVzY3JpcHRvcnM6UmUsZnJlZXplTWV0aG9kczpfdCx0b09iamVjdFNldDpWdCx0b0NhbWVsQ2FzZTpqdCxub29wOnp0LHRvRmluaXRlTnVtYmVyOlh0LGZpbmRLZXk6RmUsZ2xvYmFsOlNlLGlzQ29udGV4dERlZmluZWQ6TmUsQUxQSEFCRVQ6R2UsZ2VuZXJhdGVTdHJpbmc6dnQsaXNTcGVjQ29tcGxpYW50Rm9ybTokdCx0b0pTT05PYmplY3Q6QUksaXNBc3luY0ZuOmVJLGlzVGhlbmFibGU6dEl9O2Z1bmN0aW9uIFcoQSxlLHQsSSxyKXtFcnJvci5jYWxsKHRoaXMpLEVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsdGhpcy5jb25zdHJ1Y3Rvcik6dGhpcy5zdGFjaz1uZXcgRXJyb3IoKS5zdGFjayx0aGlzLm1lc3NhZ2U9QSx0aGlzLm5hbWU9IkF4aW9zRXJyb3IiLGUmJih0aGlzLmNvZGU9ZSksdCYmKHRoaXMuY29uZmlnPXQpLEkmJih0aGlzLnJlcXVlc3Q9SSksciYmKHRoaXMucmVzcG9uc2U9cil9cy5pbmhlcml0cyhXLEVycm9yLHt0b0pTT046ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6cy50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX19KTt2YXIgVWU9Vy5wcm90b3R5cGUsa2U9e307WyJFUlJfQkFEX09QVElPTl9WQUxVRSIsIkVSUl9CQURfT1BUSU9OIiwiRUNPTk5BQk9SVEVEIiwiRVRJTUVET1VUIiwiRVJSX05FVFdPUksiLCJFUlJfRlJfVE9PX01BTllfUkVESVJFQ1RTIiwiRVJSX0RFUFJFQ0FURUQiLCJFUlJfQkFEX1JFU1BPTlNFIiwiRVJSX0JBRF9SRVFVRVNUIiwiRVJSX0NBTkNFTEVEIiwiRVJSX05PVF9TVVBQT1JUIiwiRVJSX0lOVkFMSURfVVJMIl0uZm9yRWFjaChBPT57a2VbQV09e3ZhbHVlOkF9fSk7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVyxrZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KFVlLCJpc0F4aW9zRXJyb3IiLHt2YWx1ZTohMH0pO1cuZnJvbT0oQSxlLHQsSSxyLGkpPT57bGV0IGc9T2JqZWN0LmNyZWF0ZShVZSk7cmV0dXJuIHMudG9GbGF0T2JqZWN0KEEsZyxmdW5jdGlvbihFKXtyZXR1cm4gRSE9PUVycm9yLnByb3RvdHlwZX0sbj0+biE9PSJpc0F4aW9zRXJyb3IiKSxXLmNhbGwoZyxBLm1lc3NhZ2UsZSx0LEksciksZy5jYXVzZT1BLGcubmFtZT1BLm5hbWUsaSYmT2JqZWN0LmFzc2lnbihnLGkpLGd9O3ZhciBsPVc7dmFyIGhBPW51bGw7ZnVuY3Rpb24gS0EoQSl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChBKXx8cy5pc0FycmF5KEEpfWZ1bmN0aW9uIE9lKEEpe3JldHVybiBzLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIExlKEEsZSx0KXtyZXR1cm4gQT9BLmNvbmNhdChlKS5tYXAoZnVuY3Rpb24ocixpKXtyZXR1cm4gcj1PZShyKSwhdCYmaT8iWyIrcisiXSI6cn0pLmpvaW4odD8iLiI6IiIpOmV9ZnVuY3Rpb24gSUkoQSl7cmV0dXJuIHMuaXNBcnJheShBKSYmIUEuc29tZShLQSl9dmFyIHJJPXMudG9GbGF0T2JqZWN0KHMse30sbnVsbCxmdW5jdGlvbihlKXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QoZSl9KTtmdW5jdGlvbiBpSShBLGUsdCl7aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7ZT1lfHxuZXcoaEF8fEZvcm1EYXRhKSx0PXMudG9GbGF0T2JqZWN0KHQse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLG0pe3JldHVybiFzLmlzVW5kZWZpbmVkKG1bZl0pfSk7bGV0IEk9dC5tZXRhVG9rZW5zLHI9dC52aXNpdG9yfHxCLGk9dC5kb3RzLGc9dC5pbmRleGVzLEU9KHQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmcy5pc1NwZWNDb21wbGlhbnRGb3JtKGUpO2lmKCFzLmlzRnVuY3Rpb24ocikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBvKFEpe2lmKFE9PT1udWxsKXJldHVybiIiO2lmKHMuaXNEYXRlKFEpKXJldHVybiBRLnRvSVNPU3RyaW5nKCk7aWYoIUUmJnMuaXNCbG9iKFEpKXRocm93IG5ldyBsKCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBzLmlzQXJyYXlCdWZmZXIoUSl8fHMuaXNUeXBlZEFycmF5KFEpP0UmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtRXSk6QnVmZmVyLmZyb20oUSk6UX1mdW5jdGlvbiBCKFEsZixtKXtsZXQgdz1RO2lmKFEmJiFtJiZ0eXBlb2YgUT09Im9iamVjdCIpe2lmKHMuZW5kc1dpdGgoZiwie30iKSlmPUk/ZjpmLnNsaWNlKDAsLTIpLFE9SlNPTi5zdHJpbmdpZnkoUSk7ZWxzZSBpZihzLmlzQXJyYXkoUSkmJklJKFEpfHwocy5pc0ZpbGVMaXN0KFEpfHxzLmVuZHNXaXRoKGYsIltdIikpJiYodz1zLnRvQXJyYXkoUSkpKXJldHVybiBmPU9lKGYpLHcuZm9yRWFjaChmdW5jdGlvbihLLEpBKXshKHMuaXNVbmRlZmluZWQoSyl8fEs9PT1udWxsKSYmZS5hcHBlbmQoZz09PSEwP0xlKFtmXSxKQSxpKTpnPT09bnVsbD9mOmYrIltdIixvKEspKX0pLCExfXJldHVybiBLQShRKT8hMDooZS5hcHBlbmQoTGUobSxmLGkpLG8oUSkpLCExKX1sZXQgYz1bXSxhPU9iamVjdC5hc3NpZ24ockkse2RlZmF1bHRWaXNpdG9yOkIsY29udmVydFZhbHVlOm8saXNWaXNpdGFibGU6S0F9KTtmdW5jdGlvbiBDKFEsZil7aWYoIXMuaXNVbmRlZmluZWQoUSkpe2lmKGMuaW5kZXhPZihRKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Yy5wdXNoKFEpLHMuZm9yRWFjaChRLGZ1bmN0aW9uKHcsTyl7KCEocy5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZyLmNhbGwoZSx3LHMuaXNTdHJpbmcoTyk/Ty50cmltKCk6TyxmLGEpKT09PSEwJiZDKHcsZj9mLmNvbmNhdChPKTpbT10pfSksYy5wb3AoKX19aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBDKEEpLGV9dmFyIEo9aUk7ZnVuY3Rpb24gSmUoQSl7bGV0IGU9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIiwiJTI1MDAiOiJcXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shXCcoKX5dfCUyNTIwfCUyNTAwL2csZnVuY3Rpb24oSSl7cmV0dXJuIGVbSV19KX1mdW5jdGlvbiBNZShBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJkooQSx0aGlzLGUpfXZhciBiZT1NZS5wcm90b3R5cGU7YmUuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O2JlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24oSSl7cmV0dXJuIGUuY2FsbCh0aGlzLEksSmUpfTpKZTtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiB0KHJbMF0pKyI9Iit0KHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgZEE9TWU7ZnVuY3Rpb24gZ0koQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lMjUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNTI0L2csIiQiKS5yZXBsYWNlKC8lMjUyQy9naSwiLCIpLnJlcGxhY2UoLyUyNTIwL2csIisiKS5yZXBsYWNlKC8lMjU1Qi9naSwiWyIpLnJlcGxhY2UoLyUyNTVEL2dpLCJdIil9ZnVuY3Rpb24gQUEoQSxlLHQpe2lmKCFlKXJldHVybiBBO2xldCBJPXQmJnQuZW5jb2RlfHxnSSxyPXQmJnQuc2VyaWFsaXplLGk7aWYocj9pPXIoZSx0KTppPXMuaXNVUkxTZWFyY2hQYXJhbXMoZSk/ZS50b1N0cmluZygpOm5ldyBkQShlLHQpLnRvU3RyaW5nKEkpLGkpe2xldCBnPUEuaW5kZXhPZigiJTIzIik7ZyE9PS0xJiYoQT1BLnNsaWNlKDAsZykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIHhBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LEkpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6ST9JLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ST9JLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihJKXtJIT09bnVsbCYmZShJKX0pfX0sUEE9eEE7dmFyIG1BPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgSGU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOmRBO3ZhciBZZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIHFlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIG9JPSgoKT0+e2xldCBBO3JldHVybiB0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmKChBPW5hdmlnYXRvci5wcm9kdWN0KT09PSJSZWFjdE5hdGl2ZSJ8fEE9PT0iTmF0aXZlU2NyaXB0Inx8QT09PSJOUyIpPyExOnR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUifSkoKSxuST0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKSxEPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkhlLEZvcm1EYXRhOlllLEJsb2I6cWV9LGlzU3RhbmRhcmRCcm93c2VyRW52Om9JLGlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52Om5JLHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTtmdW5jdGlvbiBXQShBLGUpe3JldHVybiBKKEEsbmV3IEQuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LEkscixpKXtyZXR1cm4gRC5pc05vZGUmJnMuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKEksdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LGUpKX1mdW5jdGlvbiBhSShBKXtyZXR1cm4gcy5tYXRjaEFsbCgvXFx3K3xcXFsoXFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIHNJKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSksSSxyPXQubGVuZ3RoLGk7Zm9yKEk9MDtJPHI7SSsrKWk9dFtJXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gQ0koQSl7ZnVuY3Rpb24gZSh0LEkscixpKXtsZXQgZz10W2krK10sbj1OdW1iZXIuaXNGaW5pdGUoK2cpLEU9aT49dC5sZW5ndGg7cmV0dXJuIGc9IWcmJnMuaXNBcnJheShyKT9yLmxlbmd0aDpnLEU/KHMuaGFzT3duUHJvcChyLGcpP3JbZ109W3JbZ10sSV06cltnXT1JLCFuKTooKCFyW2ddfHwhcy5pc09iamVjdChyW2ddKSkmJihyW2ddPVtdKSxlKHQsSSxyW2ddLGkpJiZzLmlzQXJyYXkocltnXSkmJihyW2ddPXNJKHJbZ10pKSwhbil9aWYocy5pc0Zvcm1EYXRhKEEpJiZzLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIHMuZm9yRWFjaEVudHJ5KEEsKEkscik9PntlKGFJKEkpLHIsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIERBPUNJO3ZhciBCST17IkNvbnRlbnQtVHlwZSI6dm9pZCAwfTtmdW5jdGlvbiBRSShBLGUsdCl7aWYocy5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKGV8fEpTT04ucGFyc2UpKEEpLHMudHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgeUE9e3RyYW5zaXRpb25hbDptQSxhZGFwdGVyOlsieGhyIiwiaHR0cCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7bGV0IEk9dC5nZXRDb250ZW50VHlwZSgpfHwiIixyPUkuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLGk9cy5pc09iamVjdChlKTtpZihpJiZzLmlzSFRNTEZvcm0oZSkmJihlPW5ldyBGb3JtRGF0YShlKSkscy5pc0Zvcm1EYXRhKGUpKXJldHVybiByJiZyP0pTT04uc3RyaW5naWZ5KERBKGUpKTplO2lmKHMuaXNBcnJheUJ1ZmZlcihlKXx8cy5pc0J1ZmZlcihlKXx8cy5pc1N0cmVhbShlKXx8cy5pc0ZpbGUoZSl8fHMuaXNCbG9iKGUpKXJldHVybiBlO2lmKHMuaXNBcnJheUJ1ZmZlclZpZXcoZSkpcmV0dXJuIGUuYnVmZmVyO2lmKHMuaXNVUkxTZWFyY2hQYXJhbXMoZSkpcmV0dXJuIHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksZS50b1N0cmluZygpO2xldCBuO2lmKGkpe2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIFdBKGUsdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigobj1zLmlzRmlsZUxpc3QoZSkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEU9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBKKG4/eyJmaWxlc1tdIjplfTplLEUmJm5ldyBFLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gaXx8cj8odC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLFFJKGUpKTplfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKGUpe2xldCB0PXRoaXMudHJhbnNpdGlvbmFsfHx5QS50cmFuc2l0aW9uYWwsST10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLHI9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYoZSYmcy5pc1N0cmluZyhlKSYmKEkmJiF0aGlzLnJlc3BvbnNlVHlwZXx8cikpe2xldCBnPSEodCYmdC5zaWxlbnRKU09OUGFyc2luZykmJnI7dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpfWNhdGNoKG4pe2lmKGcpdGhyb3cgbi5uYW1lPT09IlN5bnRheEVycm9yIj9sLmZyb20obixsLkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOm59fXJldHVybiBlfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpELmNsYXNzZXMuRm9ybURhdGEsQmxvYjpELmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTIwMCYmZTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoifX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiXSxmdW5jdGlvbihlKXt5QS5oZWFkZXJzW2VdPXt9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7eUEuaGVhZGVyc1tlXT1zLm1lcmdlKEJJKX0pO3ZhciBqPXlBO3ZhciBFST1zLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLFRlPUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgJTBBYCkuZm9yRWFjaChmdW5jdGlvbihnKXtyPWcuaW5kZXhPZigiOiIpLHQ9Zy5zdWJzdHJpbmcoMCxyKS50cmltKCkudG9Mb3dlckNhc2UoKSxJPWcuc3Vic3RyaW5nKHIrMSkudHJpbSgpLCEoIXR8fGVbdF0mJkVJW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2goSSk6ZVt0XT1bSV06ZVt0XT1lW3RdP2VbdF0rIiwgIitJOkkpfSksZX07dmFyIEtlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiB3QShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6cy5pc0FycmF5KEEpP0EubWFwKHdBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gY0koQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15cXHMsOz1dKylcXHMqKD86PVxccyooW14sO10rKSk/L2csSTtmb3IoO0k9dC5leGVjKEEpOyllW0lbMV1dPUlbMl07cmV0dXJuIGV9dmFyIGZJPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhJTIzJCUmXCcqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIGpBKEEsZSx0LEkscil7aWYocy5pc0Z1bmN0aW9uKEkpKXJldHVybiBJLmNhbGwodGhpcyxlLHQpO2lmKHImJihlPXQpLCEhcy5pc1N0cmluZyhlKSl7aWYocy5pc1N0cmluZyhJKSlyZXR1cm4gZS5pbmRleE9mKEkpIT09LTE7aWYocy5pc1JlZ0V4cChJKSlyZXR1cm4gSS50ZXN0KGUpfX1mdW5jdGlvbiBsSShBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxcZF0pKFxcdyopL2csKGUsdCxJKT0+dC50b1VwcGVyQ2FzZSgpK0kpfWZ1bmN0aW9uIHVJKEEsZSl7bGV0IHQ9cy50b0NhbWVsQ2FzZSgiICIrZSk7WyJnZXQiLCJzZXQiLCJoYXMiXS5mb3JFYWNoKEk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxJK3Qse3ZhbHVlOmZ1bmN0aW9uKHIsaSxnKXtyZXR1cm4gdGhpc1tJXS5jYWxsKHRoaXMsZSxyLGksZyl9LGNvbmZpZ3VyYWJsZTohMH0pfSl9dmFyIFo9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkobixFLG8pe2xldCBCPWVBKEUpO2lmKCFCKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgYz1zLmZpbmRLZXkocixCKTsoIWN8fHJbY109PT12b2lkIDB8fG89PT0hMHx8bz09PXZvaWQgMCYmcltjXSE9PSExKSYmKHJbY3x8RV09d0EobikpfWxldCBnPShuLEUpPT5zLmZvckVhY2gobiwobyxCKT0+aShvLEIsRSkpO3JldHVybiBzLmlzUGxhaW5PYmplY3QoZSl8fGUgaW5zdGFuY2VvZiB0aGlzLmNvbnN0cnVjdG9yP2coZSx0KTpzLmlzU3RyaW5nKGUpJiYoZT1lLnRyaW0oKSkmJiFmSShlKT9nKFRlKGUpLHQpOmUhPW51bGwmJmkodCxlLEkpLHRoaXN9Z2V0KGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gY0kocik7aWYocy5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKHMuaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGpBKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkoZyl7aWYoZz1lQShnKSxnKXtsZXQgbj1zLmZpbmRLZXkoSSxnKTtuJiYoIXR8fGpBKEksSVtuXSxuLHQpKSYmKGRlbGV0ZSBJW25dLHI9ITApfX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGpBKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IGc9cy5maW5kS2V5KEksaSk7aWYoZyl7dFtnXT13QShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IG49ZT9sSShpKTpTdHJpbmcoaSkudHJpbSgpO24hPT1pJiZkZWxldGUgdFtpXSx0W25dPXdBKHIpLElbbl09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gcy5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJnMuaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYCUwQWApfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0aGlzP2U6bmV3IHRoaXMoZSl9c3RhdGljIGNvbmNhdChlLC4uLnQpe2xldCBJPW5ldyB0aGlzKGUpO3JldHVybiB0LmZvckVhY2gocj0+SS5zZXQocikpLEl9c3RhdGljIGFjY2Vzc29yKGUpe2xldCBJPSh0aGlzW0tlXT10aGlzW0tlXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLHI9dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gaShnKXtsZXQgbj1lQShnKTtJW25dfHwodUkocixnKSxJW25dPSEwKX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHRoaXN9fTtaLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtzLmZyZWV6ZU1ldGhvZHMoWi5wcm90b3R5cGUpO3MuZnJlZXplTWV0aG9kcyhaKTt2YXIgcD1aO2Z1bmN0aW9uIHRBKEEsZSl7bGV0IHQ9dGhpc3x8aixJPWV8fHQscj1wLmZyb20oSS5oZWFkZXJzKSxpPUkuZGF0YTtyZXR1cm4gcy5mb3JFYWNoKEEsZnVuY3Rpb24obil7aT1uLmNhbGwodCxpLHIubm9ybWFsaXplKCksZT9lLnN0YXR1czp2b2lkIDApfSksci5ub3JtYWxpemUoKSxpfWZ1bmN0aW9uIElBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9ZnVuY3Rpb24geGUoQSxlLHQpe2wuY2FsbCh0aGlzLEE/PyJjYW5jZWxlZCIsbC5FUlJfQ0FOQ0VMRUQsZSx0KSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IifXMuaW5oZXJpdHMoeGUsbCx7X19DQU5DRUxfXzohMH0pO3ZhciBNPXhlO2Z1bmN0aW9uIFpBKEEsZSx0KXtsZXQgST10LmNvbmZpZy52YWxpZGF0ZVN0YXR1czshdC5zdGF0dXN8fCFJfHxJKHQuc3RhdHVzKT9BKHQpOmUobmV3IGwoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIit0LnN0YXR1cyxbbC5FUlJfQkFEX1JFUVVFU1QsbC5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKHQuc3RhdHVzLzEwMCktNF0sdC5jb25maWcsdC5yZXF1ZXN0LHQpKX12YXIgUGU9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LEkscixpLGcsbil7bGV0IEU9W107RS5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChJKSkscy5pc051bWJlcihyKSYmRS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUocikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmRS5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhnKSYmRS5wdXNoKCJkb21haW49IitnKSxuPT09ITAmJkUucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPUUuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgST1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xcXFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIEk/ZGVjb2RlVVJJQ29tcG9uZW50KElbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBfQShBKXtyZXR1cm4vXihbYS16XVthLXpcXGQrXFwtLl0qOik/XFwvXFwvL2kudGVzdChBKX1mdW5jdGlvbiBWQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXFwvKyQvLCIiKSsiLyIrZS5yZXBsYWNlKC9eXFwvKy8sIiIpOkF9ZnVuY3Rpb24gckEoQSxlKXtyZXR1cm4gQSYmIV9BKGUpP1ZBKEEsZSk6ZX12YXIgV2U9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBlPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIiksSTtmdW5jdGlvbiByKGkpe2xldCBnPWk7cmV0dXJuIGUmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsZyksZz10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixnKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiUyMy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIEk9cih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oZyl7bGV0IG49cy5pc1N0cmluZyhnKT9yKGcpOmc7cmV0dXJuIG4ucHJvdG9jb2w9PT1JLnByb3RvY29sJiZuLmhvc3Q9PT1JLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIHpBKEEpe2xldCBlPS9eKFstK1xcd117MSwyNX0pKDo/XFwvXFwvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBoSShBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsZztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKEUpe2xldCBvPURhdGUubm93KCksQj1JW2ldO2d8fChnPW8pLHRbcl09RSxJW3JdPW87bGV0IGM9aSxhPTA7Zm9yKDtjIT09cjspYSs9dFtjKytdLGM9YyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksby1nPGUpcmV0dXJuO2xldCBDPUImJm8tQjtyZXR1cm4gQz9NYXRoLnJvdW5kKGEqMWUzL0MpOnZvaWQgMH19dmFyIGplPWhJO2Z1bmN0aW9uIFplKEEsZSl7bGV0IHQ9MCxJPWplKDUwLDI1MCk7cmV0dXJuIHI9PntsZXQgaT1yLmxvYWRlZCxnPXIubGVuZ3RoQ29tcHV0YWJsZT9yLnRvdGFsOnZvaWQgMCxuPWktdCxFPUkobiksbz1pPD1nO3Q9aTtsZXQgQj17bG9hZGVkOmksdG90YWw6Zyxwcm9ncmVzczpnP2kvZzp2b2lkIDAsYnl0ZXM6bixyYXRlOkV8fHZvaWQgMCxlc3RpbWF0ZWQ6RSYmZyYmbz8oZy1pKS9FOnZvaWQgMCxldmVudDpyfTtCW2U/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsQShCKX19dmFyIGRJPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsX2U9ZEkmJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LEkpe2xldCByPUEuZGF0YSxpPXAuZnJvbShBLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGc9QS5yZXNwb25zZVR5cGUsbjtmdW5jdGlvbiBFKCl7QS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShuKSxBLnNpZ25hbCYmQS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG4pfXMuaXNGb3JtRGF0YShyKSYmKEQuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEQuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/aS5zZXRDb250ZW50VHlwZSghMSk6aS5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YTsiLCExKSk7bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IEM9QS5hdXRoLnVzZXJuYW1lfHwiIixRPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoQysiOiIrUSkpfWxldCBCPXJBKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksQUEoQixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIGMoKXtpZighbylyZXR1cm47bGV0IEM9cC5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksZj17ZGF0YTohZ3x8Zz09PSJ0ZXh0Inx8Zz09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOkMsY29uZmlnOkEscmVxdWVzdDpvfTtaQShmdW5jdGlvbih3KXt0KHcpLEUoKX0sZnVuY3Rpb24odyl7SSh3KSxFKCl9LGYpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9YzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoYyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihJKG5ldyBsKCJSZXF1ZXN0IGFib3J0ZWQiLGwuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe0kobmV3IGwoIk5ldHdvcmsgRXJyb3IiLGwuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBRPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixmPUEudHJhbnNpdGlvbmFsfHxtQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihRPUEudGltZW91dEVycm9yTWVzc2FnZSksSShuZXcgbChRLGYuY2xhcmlmeVRpbWVvdXRFcnJvcj9sLkVUSU1FRE9VVDpsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LEQuaXNTdGFuZGFyZEJyb3dzZXJFbnYpe2xldCBDPShBLndpdGhDcmVkZW50aWFsc3x8V2UoQikpJiZBLnhzcmZDb29raWVOYW1lJiZQZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO0MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsQyl9cj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBvJiZzLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihRLGYpe28uc2V0UmVxdWVzdEhlYWRlcihmLFEpfSkscy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChvLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxnJiZnIT09Impzb24iJiYoby5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLnVwbG9hZCYmby51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihuPUM9PntvJiYoSSghQ3x8Qy50eXBlP25ldyBNKG51bGwsQSxvKTpDKSxvLmFib3J0KCksbz1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobiksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP24oKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbikpKTtsZXQgYT16QShCKTtpZihhJiZELnByb3RvY29scy5pbmRleE9mKGEpPT09LTEpe0kobmV3IGwoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrYSsiOiIsbC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1vLnNlbmQocnx8bnVsbCl9KX07dmFyIHBBPXtodHRwOmhBLHhocjpfZX07cy5mb3JFYWNoKHBBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyIFZlPXtnZXRBZGFwdGVyOkE9PntBPXMuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsdCxJO2ZvcihsZXQgcj0wO3I8ZSYmKHQ9QVtyXSwhKEk9cy5pc1N0cmluZyh0KT9wQVt0LnRvTG93ZXJDYXNlKCldOnQpKTtyKyspO2lmKCFJKXRocm93IEk9PT0hMT9uZXcgbChgQWRhcHRlciAke3R9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50YCwiRVJSX05PVF9TVVBQT1JUIik6bmV3IEVycm9yKHMuaGFzT3duUHJvcChwQSx0KT9gQWRhcHRlciBcJyR7dH1cJyBpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZGA6YFVua25vd24gYWRhcHRlciBcJyR7dH1cJ2ApO2lmKCFzLmlzRnVuY3Rpb24oSSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiYWRhcHRlciBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBJfSxhZGFwdGVyczpwQX07ZnVuY3Rpb24gWEEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IE0obnVsbCxBKX1mdW5jdGlvbiBGQShBKXtyZXR1cm4gWEEoQSksQS5oZWFkZXJzPXAuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksVmUuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fGouYWRhcHRlcikoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gWEEoQSksSS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1wLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gSUEoSSl8fChYQShBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1wLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIHplPUE9PkEgaW5zdGFuY2VvZiBwP0EudG9KU09OKCk6QTtmdW5jdGlvbiBrKEEsZSl7ZT1lfHx7fTtsZXQgdD17fTtmdW5jdGlvbiBJKG8sQixjKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KG8pJiZzLmlzUGxhaW5PYmplY3QoQik/cy5tZXJnZS5jYWxsKHtjYXNlbGVzczpjfSxvLEIpOnMuaXNQbGFpbk9iamVjdChCKT9zLm1lcmdlKHt9LEIpOnMuaXNBcnJheShCKT9CLnNsaWNlKCk6Qn1mdW5jdGlvbiByKG8sQixjKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyxjKX1lbHNlIHJldHVybiBJKG8sQixjKX1mdW5jdGlvbiBpKG8sQil7aWYoIXMuaXNVbmRlZmluZWQoQikpcmV0dXJuIEkodm9pZCAwLEIpfWZ1bmN0aW9uIGcobyxCKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyl9ZWxzZSByZXR1cm4gSSh2b2lkIDAsQil9ZnVuY3Rpb24gbihvLEIsYyl7aWYoYyBpbiBlKXJldHVybiBJKG8sQik7aWYoYyBpbiBBKXJldHVybiBJKHZvaWQgMCxvKX1sZXQgRT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsYWRhcHRlcjpnLHJlc3BvbnNlVHlwZTpnLHhzcmZDb29raWVOYW1lOmcseHNyZkhlYWRlck5hbWU6ZyxvblVwbG9hZFByb2dyZXNzOmcsb25Eb3dubG9hZFByb2dyZXNzOmcsZGVjb21wcmVzczpnLG1heENvbnRlbnRMZW5ndGg6ZyxtYXhCb2R5TGVuZ3RoOmcsYmVmb3JlUmVkaXJlY3Q6Zyx0cmFuc3BvcnQ6ZyxodHRwQWdlbnQ6ZyxodHRwc0FnZW50OmcsY2FuY2VsVG9rZW46Zyxzb2NrZXRQYXRoOmcscmVzcG9uc2VFbmNvZGluZzpnLHZhbGlkYXRlU3RhdHVzOm4saGVhZGVyczoobyxCKT0+cih6ZShvKSx6ZShCKSwhMCl9O3JldHVybiBzLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihCKXtsZXQgYz1FW0JdfHxyLGE9YyhBW0JdLGVbQl0sQik7cy5pc1VuZGVmaW5lZChhKSYmYyE9PW58fCh0W0JdPWEpfSksdH12YXIgU0E9IjEuNC4wIjt2YXIgdkE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57dkFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIFhlPXt9O3ZBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQsSSl7ZnVuY3Rpb24gcihpLGcpe3JldHVybiJbQXhpb3MgdiIrU0ErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIraSsiXCciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4oaSxnLG4pPT57aWYoZT09PSExKXRocm93IG5ldyBsKHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksbC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFYZVtnXSYmKFhlW2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKGksZyxuKTohMH19O2Z1bmN0aW9uIG1JKEEsZSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGwoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgaT1JW3JdLGc9ZVtpXTtpZihnKXtsZXQgbj1BW2ldLEU9bj09PXZvaWQgMHx8ZyhuLGksQSk7aWYoRSE9PSEwKXRocm93IG5ldyBsKCJvcHRpb24gIitpKyIgbXVzdCBiZSAiK0UsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyBsKCJVbmtub3duIG9wdGlvbiAiK2ksbC5FUlJfQkFEX09QVElPTil9fXZhciBOQT17YXNzZXJ0T3B0aW9uczptSSx2YWxpZGF0b3JzOnZBfTt2YXIgYj1OQS52YWxpZGF0b3JzLF89Y2xhc3N7Y29uc3RydWN0b3IoZSl7dGhpcy5kZWZhdWx0cz1lLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBQQSxyZXNwb25zZTpuZXcgUEF9fXJlcXVlc3QoZSx0KXt0eXBlb2YgZT09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9ZSk6dD1lfHx7fSx0PWsodGhpcy5kZWZhdWx0cyx0KTtsZXR7dHJhbnNpdGlvbmFsOkkscGFyYW1zU2VyaWFsaXplcjpyLGhlYWRlcnM6aX09dDtJIT09dm9pZCAwJiZOQS5hc3NlcnRPcHRpb25zKEkse3NpbGVudEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Yi50cmFuc2l0aW9uYWwoYi5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbil9LCExKSxyIT1udWxsJiYocy5pc0Z1bmN0aW9uKHIpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9Ok5BLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOmIuZnVuY3Rpb24sc2VyaWFsaXplOmIuZnVuY3Rpb259LCEwKSksdC5tZXRob2Q9KHQubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGc7Zz1pJiZzLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKSxnJiZzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBpW1FdfSksdC5oZWFkZXJzPXAuY29uY2F0KGcsaSk7bGV0IG49W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7dHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITF8fChFPUUmJmYuc3luY2hyb25vdXMsbi51bnNoaWZ0KGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpKX0pO2xldCBvPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZil7by5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IEIsYz0wLGE7aWYoIUUpe2xldCBRPVtGQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKFEudW5zaGlmdC5hcHBseShRLG4pLFEucHVzaC5hcHBseShRLG8pLGE9US5sZW5ndGgsQj1Qcm9taXNlLnJlc29sdmUodCk7YzxhOylCPUIudGhlbihRW2MrK10sUVtjKytdKTtyZXR1cm4gQn1hPW4ubGVuZ3RoO2xldCBDPXQ7Zm9yKGM9MDtjPGE7KXtsZXQgUT1uW2MrK10sZj1uW2MrK107dHJ5e0M9UShDKX1jYXRjaChtKXtmLmNhbGwodGhpcyxtKTticmVha319dHJ5e0I9RkEuY2FsbCh0aGlzLEMpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3IoYz0wLGE9by5sZW5ndGg7YzxhOylCPUIudGhlbihvW2MrK10sb1tjKytdKTtyZXR1cm4gQn1nZXRVcmkoZSl7ZT1rKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9ckEoZS5iYXNlVVJMLGUudXJsKTtyZXR1cm4gQUEodCxlLnBhcmFtcyxlLnBhcmFtc1NlcmlhbGl6ZXIpfX07cy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihlKXtfLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LEkpe3JldHVybiB0aGlzLnJlcXVlc3QoayhJfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChJKXtyZXR1cm4gZnVuY3Rpb24oaSxnLG4pe3JldHVybiB0aGlzLnJlcXVlc3QoayhufHx7fSx7bWV0aG9kOmUsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDppLGRhdGE6Z30pKX19Xy5wcm90b3R5cGVbZV09dCgpLF8ucHJvdG90eXBlW2UrIkZvcm0iXT10KCEwKX0pO3ZhciBpQT1fO3ZhciAkQT1jbGFzcyBBe2NvbnN0cnVjdG9yKGUpe2lmKHR5cGVvZiBlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dD1pfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IGk9SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2ktLSA+MDspSS5fbGlzdGVuZXJzW2ldKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBpLGc9bmV3IFByb21pc2Uobj0+e0kuc3Vic2NyaWJlKG4pLGk9bn0pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShpKX0sZ30sZShmdW5jdGlvbihpLGcsbil7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgTShpLGcsbiksdChJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfXVuc3Vic2NyaWJlKGUpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKGUpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgZTtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24ocil7ZT1yfSksY2FuY2VsOmV9fX0sdmU9JEE7ZnVuY3Rpb24gQWUoQSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBBLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGVlKEEpe3JldHVybiBzLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciB0ZT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXModGUpLmZvckVhY2goKFtBLGVdKT0+e3RlW2VdPUF9KTt2YXIgJGU9dGU7ZnVuY3Rpb24gQXQoQSl7bGV0IGU9bmV3IGlBKEEpLHQ9WChpQS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gcy5leHRlbmQodCxpQS5wcm90b3R5cGUsZSx7YWxsT3duS2V5czohMH0pLHMuZXh0ZW5kKHQsZSxudWxsLHthbGxPd25LZXlzOiEwfSksdC5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIEF0KGsoQSxyKSl9LHR9dmFyIGg9QXQoaik7aC5BeGlvcz1pQTtoLkNhbmNlbGVkRXJyb3I9TTtoLkNhbmNlbFRva2VuPXZlO2guaXNDYW5jZWw9SUE7aC5WRVJTSU9OPVNBO2gudG9Gb3JtRGF0YT1KO2guQXhpb3NFcnJvcj1sO2guQ2FuY2VsPWguQ2FuY2VsZWRFcnJvcjtoLmFsbD1mdW5jdGlvbihlKXtyZXR1cm4gUHJvbWlzZS5hbGwoZSl9O2guc3ByZWFkPUFlO2guaXNBeGlvc0Vycm9yPWVlO2gubWVyZ2VDb25maWc9aztoLkF4aW9zSGVhZGVycz1wO2guZm9ybVRvSlNPTj1BPT5EQShzLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO2guSHR0cFN0YXR1c0NvZGU9JGU7aC5kZWZhdWx0PWg7dmFyIFJBPWg7dmFye0F4aW9zOlNnLEF4aW9zRXJyb3I6TmcsQ2FuY2VsZWRFcnJvcjpSZyxpc0NhbmNlbDpHZyxDYW5jZWxUb2tlbjpVZyxWRVJTSU9OOmtnLGFsbDpMZyxDYW5jZWw6T2csaXNBeGlvc0Vycm9yOkpnLHNwcmVhZDpNZyx0b0Zvcm1EYXRhOmJnLEF4aW9zSGVhZGVyczpIZyxIdHRwU3RhdHVzQ29kZTpZZyxmb3JtVG9KU09OOnFnLG1lcmdlQ29uZmlnOlRnfT1SQTt2YXIgZ0EsTCxyZSxJZT17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe3JlPW5ldyBVaW50OEFycmF5KEwuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSxHQT1jbGFzc3tpbml0KCl7cmV0dXJuIGdBfHwodHlwZW9mIGZldGNoPCJ1Ij9nQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK2V0KS50aGVuKGU9PmUuYXJyYXlCdWZmZXIoKSkudGhlbihlPT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShlLEllKSkudGhlbih0aGlzLl9pbml0KTpnQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbShldCwiYmFzZTY0IiksSWUpLnRoZW4odGhpcy5faW5pdCksZ0EpfV9pbml0KGUpe0w9ZS5pbnN0YW5jZSxJZS5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUoZSx0PTApe2lmKCFMKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBJPWUuYnl0ZUxlbmd0aCxyPUwuZXhwb3J0cy5tYWxsb2MoSSk7cmUuc2V0KGUsciksdD10fHxOdW1iZXIoTC5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUocixJKSk7bGV0IGk9TC5leHBvcnRzLm1hbGxvYyh0KSxnPUwuZXhwb3J0cy5aU1REX2RlY29tcHJlc3MoaSx0LHIsSSksbj1yZS5zbGljZShpLGkrZyk7cmV0dXJuIEwuZXhwb3J0cy5mcmVlKHIpLEwuZXhwb3J0cy5mcmVlKGkpLG59fSxldD0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciB0dD1uZXcgR0EsSXQ9ITE7YXN5bmMgZnVuY3Rpb24gREkoQSxlKXtsZXQgdD1udWxsO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IEk9YCR7dH0ud2FzbWAscj1hd2FpdCBSQS5nZXQoYCR7SX0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KTtJdHx8KGF3YWl0IHR0LmluaXQoKSxJdD0hMCk7bGV0IGc9dHQuZGVjb2RlKG5ldyBVaW50OEFycmF5KHIuZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6Z30pfXZhciBydD1ESTt2YXIgVUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiB5SShBLGUpe2xldCB0PUEsST1BLHI9bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYodD1uZXcgVVJMKEEuaHJlZiksST10LmhyZWYpLFVBLmhhcyhJKXx8VUEuc2V0KEksYXdhaXQgcnQodCxlKSkscj1VQS5nZXQoSSkscn12YXIgRz15STt2YXIgd0k9bmV3IE1hcChbWyJpbWFnZS9qcGVnIiwiSlBFR0ltYWdlSU8iXSxbImltYWdlL3BuZyIsIlBOR0ltYWdlSU8iXSxbImltYWdlL3RpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiaW1hZ2UveC1tcy1ibXAiLCJCTVBJbWFnZUlPIl0sWyJpbWFnZS94LWJtcCIsIkJNUEltYWdlSU8iXSxbImltYWdlL2JtcCIsIkJNUEltYWdlSU8iXSxbImFwcGxpY2F0aW9uL2RpY29tIiwiR0RDTUltYWdlSU8iXV0pLGllPXdJO3ZhciBwST1uZXcgTWFwKFtbImJtcCIsIkJNUEltYWdlSU8iXSxbIkJNUCIsIkJNUEltYWdlSU8iXSxbImRjbSIsIkdEQ01JbWFnZUlPIl0sWyJEQ00iLCJHRENNSW1hZ2VJTyJdLFsiZ2lwbCIsIkdpcGxJbWFnZUlPIl0sWyJnaXBsLmd6IiwiR2lwbEltYWdlSU8iXSxbImhkZjUiLCJIREY1SW1hZ2VJTyJdLFsianBnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRyIsIkpQRUdJbWFnZUlPIl0sWyJqcGVnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRUciLCJKUEVHSW1hZ2VJTyJdLFsiaXdpIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yLnpzdCIsIldhc21ac3RkSW1hZ2VJTyJdLFsibHNtIiwiTFNNSW1hZ2VJTyJdLFsibW5jIiwiTUlOQ0ltYWdlSU8iXSxbIk1OQyIsIk1JTkNJbWFnZUlPIl0sWyJtbmMuZ3oiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DLkdaIiwiTUlOQ0ltYWdlSU8iXSxbIm1uYzIiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DMiIsIk1JTkNJbWFnZUlPIl0sWyJtZ2giLCJNR0hJbWFnZUlPIl0sWyJtZ3oiLCJNR0hJbWFnZUlPIl0sWyJtZ2guZ3oiLCJNR0hJbWFnZUlPIl0sWyJtaGEiLCJNZXRhSW1hZ2VJTyJdLFsibWhkIiwiTWV0YUltYWdlSU8iXSxbIm1yYyIsIk1SQ0ltYWdlSU8iXSxbIm5pYSIsIk5pZnRpSW1hZ2VJTyJdLFsibmlpIiwiTmlmdGlJbWFnZUlPIl0sWyJuaWkuZ3oiLCJOaWZ0aUltYWdlSU8iXSxbImhkciIsIk5pZnRpSW1hZ2VJTyJdLFsibnJyZCIsIk5ycmRJbWFnZUlPIl0sWyJOUlJEIiwiTnJyZEltYWdlSU8iXSxbIm5oZHIiLCJOcnJkSW1hZ2VJTyJdLFsiTkhEUiIsIk5ycmRJbWFnZUlPIl0sWyJwbmciLCJQTkdJbWFnZUlPIl0sWyJQTkciLCJQTkdJbWFnZUlPIl0sWyJwaWMiLCJCaW9SYWRJbWFnZUlPIl0sWyJQSUMiLCJCaW9SYWRJbWFnZUlPIl0sWyJ0aWYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGIiwiVElGRkltYWdlSU8iXSxbInRpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGRiIsIlRJRkZJbWFnZUlPIl0sWyJ2dGsiLCJWVEtJbWFnZUlPIl0sWyJWVEsiLCJWVEtJbWFnZUlPIl0sWyJpc3EiLCJTY2FuY29JbWFnZUlPIl0sWyJJU1EiLCJTY2FuY29JbWFnZUlPIl0sWyJmZGYiLCJGREZJbWFnZUlPIl0sWyJGREYiLCJGREZJbWFnZUlPIl1dKSxnZT1wSTtmdW5jdGlvbiBGSShBKXtsZXQgZT1BLnNsaWNlKChBLmxhc3RJbmRleE9mKCIuIiktMT4+PjApKzIpO2lmKGUudG9Mb3dlckNhc2UoKT09PSJneiIpe2xldCB0PUEuc2xpY2UoMCwtMykubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoZS50b0xvd2VyQ2FzZSgpPT09ImNib3IiKXtsZXQgdD1BLnNsaWNlKDAsLTUpLmxhc3RJbmRleE9mKCIuIik7ZT1BLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKGUudG9Mb3dlckNhc2UoKT09PSJ6c3QiKXtsZXQgdD1BLnNsaWNlKDAsLTEwKS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihlLnRvTG93ZXJDYXNlKCk9PT0iemlwIil7bGV0IHQ9QS5zbGljZSgwLC00KS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9cmV0dXJuIGV9dmFyIGtBPUZJO3ZhciBTST1bIlBOR0ltYWdlSU8iLCJNZXRhSW1hZ2VJTyIsIlRJRkZJbWFnZUlPIiwiTmlmdGlJbWFnZUlPIiwiSlBFR0ltYWdlSU8iLCJOcnJkSW1hZ2VJTyIsIlZUS0ltYWdlSU8iLCJCTVBJbWFnZUlPIiwiSERGNUltYWdlSU8iLCJNSU5DSW1hZ2VJTyIsIk1SQ0ltYWdlSU8iLCJMU01JbWFnZUlPIiwiTUdISW1hZ2VJTyIsIkJpb1JhZEltYWdlSU8iLCJHaXBsSW1hZ2VJTyIsIkdFQWR3SW1hZ2VJTyIsIkdFNEltYWdlSU8iLCJHRTVJbWFnZUlPIiwiR0RDTUltYWdlSU8iLCJTY2FuY29JbWFnZUlPIiwiRkRGSW1hZ2VJTyIsIldhc21JbWFnZUlPIiwiV2FzbVpzdGRJbWFnZUlPIl0sTEE9U0k7dmFyIE5JPXtUZXh0RmlsZToiSW50ZXJmYWNlVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkludGVyZmFjZUJpbmFyeUZpbGUiLFRleHRTdHJlYW06IkludGVyZmFjZVRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiSW50ZXJmYWNlQmluYXJ5U3RyZWFtIixJbWFnZToiSW50ZXJmYWNlSW1hZ2UiLE1lc2g6IkludGVyZmFjZU1lc2giLFBvbHlEYXRhOiJJbnRlcmZhY2VQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6IkludGVyZmFjZUpzb25Db21wYXRpYmxlIn0sdT1OSTt2YXIgUkk9e1RleHQ6IlRleHQiLEJpbmFyeToiQmluYXJ5IixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2gifSxTPVJJO3ZhciBHST17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEY9R0k7dmFyIFVJPXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxUPVVJO2Z1bmN0aW9uIGtJKEEsZSl7bGV0IHQ9bnVsbDtzd2l0Y2goQSl7Y2FzZSBGLlVJbnQ4Ont0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ4Ont0PW5ldyBJbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQxNjp7dD1uZXcgVWludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDE2Ont0PW5ldyBJbnQxNkFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50MzI6e3Q9bmV3IFVpbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQzMjp7dD1uZXcgSW50MzJBcnJheShlKTticmVha31jYXNlIEYuVUludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdVaW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdVaW50NjRBcnJheShlKTp0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnSW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdJbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBULkZsb2F0MzI6e3Q9bmV3IEZsb2F0MzJBcnJheShlKTticmVha31jYXNlIFQuRmxvYXQ2NDp7dD1uZXcgRmxvYXQ2NEFycmF5KGUpO2JyZWFrfWNhc2UibnVsbCI6e3Q9bnVsbDticmVha31jYXNlIG51bGw6e3Q9bnVsbDticmVha31kZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVHlwZSBpcyBub3Qgc3VwcG9ydGVkIGFzIGEgVHlwZWRBcnJheSIpfXJldHVybiB0fXZhciBkPWtJO3ZhciBvdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixpdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoQSxlKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3BlbihlLHQuZmxhZ3MpLGk9QS5mc19zdGF0KGUpLnNpemUsZz1udWxsO290P2c9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGkpOmc9bmV3IEFycmF5QnVmZmVyKGkpO2xldCBuPW5ldyBVaW50OEFycmF5KGcpO3JldHVybiBBLmZzX3JlYWQoSSxuLDAsaSwwKSxBLmZzX2Nsb3NlKEkpLG59ZnVuY3Rpb24gbnQoQSxlLHQpe2xldCBJPW51bGw7b3Q/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ST1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksaT1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsZSx0KTtyZXR1cm4gci5zZXQoaSkscn1mdW5jdGlvbiB5KEEsZSx0LEkpe2xldCByPTA7cmV0dXJuIGUhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEksZS5idWZmZXIuYnl0ZUxlbmd0aF0pLEEuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShlLmJ1ZmZlcikscikpLHJ9ZnVuY3Rpb24gVihBLGUsdCl7bGV0IEk9SlNPTi5zdHJpbmdpZnkoZSkscj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsSS5sZW5ndGhdKTtBLndyaXRlQXNjaWlUb01lbW9yeShJLHIsITEpfWZ1bmN0aW9uIE4oQSxlLHQsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksaT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxnPW50KEEscixpKTtyZXR1cm4gZChJLGcuYnVmZmVyKX1mdW5jdGlvbiBvZShBLGUpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsZV0pLEk9QS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKEkpfWZ1bmN0aW9uIExJKEEsZSx0LEkpe0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihvLEIpe3ZhciBjO3N3aXRjaChvLnR5cGUpe2Nhc2UgdS5UZXh0U3RyZWFtOntsZXQgYT1pdC5lbmNvZGUoby5kYXRhLmRhdGEpLEM9eShBLGEsQiwwKSxRPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07VihBLFEsQik7YnJlYWt9Y2FzZSB1Lkpzb25Db21wYXRpYmxlOntsZXQgYT1pdC5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoby5kYXRhKSksQz15KEEsYSxCLDApLFE9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTtWKEEsUSxCKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgYT1vLmRhdGEuZGF0YSxDPXkoQSxhLEIsMCksUT17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1YoQSxRLEIpO2JyZWFrfWNhc2UgdS5UZXh0RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgdS5CaW5hcnlGaWxlOntBLmZzX3dyaXRlRmlsZShvLmRhdGEucGF0aCxvLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSB1LkltYWdlOntsZXQgYT1vLmRhdGEsQz15KEEsYS5kYXRhLEIsMCksUT15KEEsYS5kaXJlY3Rpb24sQiwxKSxmPXR5cGVvZigoYz1hLm1ldGFkYXRhKT09PW51bGx8fGM9PT12b2lkIDA/dm9pZCAwOmMuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20oYS5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLG09e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLHNpemU6YS5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsbWV0YWRhdGE6Zn07VihBLG0sQik7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBhPW8uZGF0YSxDPXkoQSxhLnBvaW50cyxCLDApLFE9eShBLGEuY2VsbHMsQiwxKSxmPXkoQSxhLnBvaW50RGF0YSxCLDIpLG09eShBLGEuY2VsbERhdGEsQiwzKSx3PXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YH07VihBLHcsQik7YnJlYWt9Y2FzZSB1LlBvbHlEYXRhOntsZXQgYT1vLmRhdGEsQz15KEEsYS5wb2ludHMsQiwwKSxRPXkoQSxhLnZlcnRpY2VzLEIsMSksZj15KEEsYS5saW5lcyxCLDIpLG09eShBLGEucG9seWdvbnMsQiwzKSx3PXkoQSxhLnRyaWFuZ2xlU3RyaXBzLEIsNCksTz15KEEsYS5wb2ludERhdGEsQiw1KSxLPXkoQSxhLnBvaW50RGF0YSxCLDYpLEpBPXtwb2x5RGF0YVR5cGU6YS5wb2x5RGF0YVR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsdmVydGljZXNCdWZmZXJTaXplOmEudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGxpbmVzQnVmZmVyU2l6ZTphLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxwb2x5Z29uc0J1ZmZlclNpemU6YS5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOmEudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7d31gLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke099YCxudW1iZXJPZkNlbGxQaXhlbHM6YS5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtLfWB9O1YoQSxKQSxCKTticmVha31jYXNlIFMuVGV4dDp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkJpbmFyeTp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkltYWdlOntsZXQgYT1vLmRhdGEsQz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTphLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoQykpLGEuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5kYXRhLmJ1ZmZlcikpLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShhLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFMuTWVzaDp7bGV0IGE9by5kYXRhLEM9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZX07aWYoQS5mc19ta2RpcnMoYCR7by5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShDKSksQy5udW1iZXJPZlBvaW50cz4wKXtpZihhLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5wb2ludHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKGEucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShhLnBvaW50RGF0YS5idWZmZXIpKX1pZihDLm51bWJlck9mQ2VsbHM+MCl7aWYoYS5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYoYS5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLEEucmVzZXRNb2R1bGVTdGRvdXQoKSxBLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IHI9QS5zdGFja1NhdmUoKSxpPTA7dHJ5e2k9QS5jYWxsTWFpbihlLnNsaWNlKCkpfWNhdGNoKG8pe3Rocm93IHR5cGVvZiBvPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsQS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsQS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIEEuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsQS5nZXRFeGNlcHRpb25NZXNzYWdlKG8pKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLG99ZmluYWxseXtBLnN0YWNrUmVzdG9yZShyKX1sZXQgZz1BLmdldE1vZHVsZVN0ZG91dCgpLG49QS5nZXRNb2R1bGVTdGRlcnIoKSxFPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZpPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKG8sQil7bGV0IGM9bnVsbDtzd2l0Y2goby50eXBlKXtjYXNlIHUuVGV4dFN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLFEpO2M9e2RhdGE6Z3QuZGVjb2RlKGYpfTticmVha31jYXNlIHUuSnNvbkNvbXBhdGlibGU6e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksZj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsQyxRKTtjPUpTT04ucGFyc2UoZ3QuZGVjb2RlKGYpKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pO2M9e2RhdGE6bnQoQSxDLFEpfTticmVha31jYXNlIHUuVGV4dEZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpBLmZzX3JlYWRGaWxlKG8uZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSB1LkJpbmFyeUZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpIKEEsby5kYXRhLnBhdGgpfTticmVha31jYXNlIHUuSW1hZ2U6e2xldCBDPW9lKEEsQik7Qy5kYXRhPU4oQSxCLDAsQy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQy5kaXJlY3Rpb249TihBLEIsMSxULkZsb2F0NjQpLEMubWV0YWRhdGE9bmV3IE1hcChDLm1ldGFkYXRhKSxjPUM7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkMucG9pbnRzPWQoQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbHM+MD9DLmNlbGxzPU4oQSxCLDEsQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qy5jZWxscz1kKEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiwyLEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPWQoQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1OKEEsQiwzLEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGM9QzticmVha31jYXNlIHUuUG9seURhdGE6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsVC5GbG9hdDMyKTpDLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEMudmVydGljZXNCdWZmZXJTaXplPjA/Qy52ZXJ0aWNlcz1OKEEsQiwxLEYuVUludDMyKTpDLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxDLmxpbmVzQnVmZmVyU2l6ZT4wP0MubGluZXM9TihBLEIsMixGLlVJbnQzMik6Qy5saW5lcz1uZXcgVWludDMyQXJyYXksQy5wb2x5Z29uc0J1ZmZlclNpemU+MD9DLnBvbHlnb25zPU4oQSxCLDMsRi5VSW50MzIpOkMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qy50cmlhbmdsZVN0cmlwcz1OKEEsQiw0LEYuVUludDMyKTpDLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiw1LEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpDLnBvaW50RGF0YT1kKEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxQaXhlbHM+MD9DLmNlbGxEYXRhPU4oQSxCLDYsQy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxjPUM7YnJlYWt9Y2FzZSBTLlRleHQ6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtjPUEuZnNfcmVhZEZpbGUoby5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFMuQmluYXJ5OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Yz1IKEEsby5wYXRoKTticmVha31jYXNlIFMuSW1hZ2U6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgQz1BLmZzX3JlYWRGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLFE9SlNPTi5wYXJzZShDKSxmPUgoQSxgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtRLmRhdGE9ZChRLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGYuYnVmZmVyKTtsZXQgbT1IKEEsYCR7by5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtRLmRpcmVjdGlvbj1kKFQuRmxvYXQ2NCxtLmJ1ZmZlciksYz1RO2JyZWFrfWNhc2UgUy5NZXNoOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEM9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxRPUpTT04ucGFyc2UoQyk7aWYoUS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtRLnBvaW50cz1kKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnRzPWQoUS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihRLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7US5wb2ludERhdGE9ZChRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnREYXRhPWQoUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKFEubnVtYmVyT2ZDZWxscz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO1EuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoUS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtRLmNlbGxEYXRhPWQoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbERhdGE9ZChRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtjPVE7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgYT17dHlwZTpvLnR5cGUsZGF0YTpjfTtFLnB1c2goYSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6ZyxzdGRlcnI6bixvdXRwdXRzOkV9fXZhciB6PUxJO3ZhciBvQT1mdW5jdGlvbihBKXtyZXR1cm4gdGhpcyBpbnN0YW5jZW9mIG9BPyh0aGlzLnY9QSx0aGlzKTpuZXcgb0EoQSl9LE9JPWZ1bmN0aW9uKEEsZSx0KXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIEk9dC5hcHBseShBLGV8fFtdKSxyLGk9W107cmV0dXJuIHI9e30sZygibmV4dCIpLGcoInRocm93IiksZygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scjtmdW5jdGlvbiBnKGEpe0lbYV0mJihyW2FdPWZ1bmN0aW9uKEMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihRLGYpe2kucHVzaChbYSxDLFEsZl0pPjF8fG4oYSxDKX0pfSl9ZnVuY3Rpb24gbihhLEMpe3RyeXtFKElbYV0oQykpfWNhdGNoKFEpe2MoaVswXVszXSxRKX19ZnVuY3Rpb24gRShhKXthLnZhbHVlIGluc3RhbmNlb2Ygb0E/UHJvbWlzZS5yZXNvbHZlKGEudmFsdWUudikudGhlbihvLEIpOmMoaVswXVsyXSxhKX1mdW5jdGlvbiBvKGEpe24oIm5leHQiLGEpfWZ1bmN0aW9uIEIoYSl7bigidGhyb3ciLGEpfWZ1bmN0aW9uIGMoYSxDKXthKEMpLGkuc2hpZnQoKSxpLmxlbmd0aCYmbihpWzBdWzBdLGlbMF1bMV0pfX0sSkk9ZnVuY3Rpb24oQSl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBlPUFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdLHQ7cmV0dXJuIGU/ZS5jYWxsKEEpOihBPXR5cGVvZiBfX3ZhbHVlcz09ImZ1bmN0aW9uIj9fX3ZhbHVlcyhBKTpBW1N5bWJvbC5pdGVyYXRvcl0oKSx0PXt9LEkoIm5leHQiKSxJKCJ0aHJvdyIpLEkoInJldHVybiIpLHRbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHQpO2Z1bmN0aW9uIEkoaSl7dFtpXT1BW2ldJiZmdW5jdGlvbihnKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obixFKXtnPUFbaV0oZykscihuLEUsZy5kb25lLGcudmFsdWUpfSl9fWZ1bmN0aW9uIHIoaSxnLG4sRSl7UHJvbWlzZS5yZXNvbHZlKEUpLnRoZW4oZnVuY3Rpb24obyl7aSh7dmFsdWU6byxkb25lOm59KX0sZyl9fTtmdW5jdGlvbiBNSShBKXtyZXR1cm4gT0kodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24qKCl7Zm9yKGxldCB0PTA7dDxMQS5sZW5ndGg7dCsrKXtsZXQgST1MQVt0XSsiLXJlYWQtaW1hZ2UiLHI9eWllbGQgb0EoRyhJLEEuY29uZmlnLmltYWdlSU9VcmwpKTt5aWVsZCB5aWVsZCBvQShyKX19KX1hc3luYyBmdW5jdGlvbiBiSShBLGUpe3ZhciB0LEk7aWYoQS5taW1lVHlwZSYmaWUuaGFzKEEubWltZVR5cGUpKXtsZXQgbj1pZS5nZXQoQS5taW1lVHlwZSkrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLmltYWdlSU9VcmwpfWxldCByPWtBKEEuZmlsZU5hbWUpO2lmKGdlLmhhcyhyKSl7bGV0IG49Z2UuZ2V0KHIpK2U7cmV0dXJuIGF3YWl0IEcobixBLmNvbmZpZy5pbWFnZUlPVXJsKX1mb3IobGV0IG49MDtuPExBLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsSkkoTUkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBuZT1iSTt2YXIgSEk9bmV3IE1hcChbXSksYWU9SEk7dmFyIFlJPW5ldyBNYXAoW1sidnRrIiwiVlRLUG9seURhdGFNZXNoSU8iXSxbIlZUSyIsIlZUS1BvbHlEYXRhTWVzaElPIl0sWyJieXUiLCJCWVVNZXNoSU8iXSxbIkJZVSIsIkJZVU1lc2hJTyJdLFsiZnNhIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIl0sWyJGU0EiLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iXSxbImZzYiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIkZTQiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIm9iaiIsIk9CSk1lc2hJTyJdLFsiT0JKIiwiT0JKTWVzaElPIl0sWyJvZmYiLCJPRkZNZXNoSU8iXSxbIk9GRiIsIk9GRk1lc2hJTyJdLFsic3RsIiwiU1RMTWVzaElPIl0sWyJTVEwiLCJTVExNZXNoSU8iXSxbInN3YyIsIlNXQ01lc2hJTyJdLFsiU1dDIiwiU1dDTWVzaElPIl0sWyJpd20iLCJXYXNtTWVzaElPIl0sWyJpd20uY2JvciIsIldhc21NZXNoSU8iXSxbIml3bS5jYm9yLnpzdCIsIldhc21ac3RkTWVzaElPIl1dKSxzZT1ZSTt2YXIgcUk9WyJCWVVNZXNoSU8iLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIiwiT0JKTWVzaElPIiwiT0ZGTWVzaElPIiwiU1RMTWVzaElPIiwiU1dDTWVzaElPIiwiVlRLUG9seURhdGFNZXNoSU8iLCJXYXNtTWVzaElPIiwiV2FzbVpzdGRNZXNoSU8iXSxPQT1xSTt2YXIgbkE9ZnVuY3Rpb24oQSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBuQT8odGhpcy52PUEsdGhpcyk6bmV3IG5BKEEpfSxUST1mdW5jdGlvbihBLGUsdCl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBJPXQuYXBwbHkoQSxlfHxbXSkscixpPVtdO3JldHVybiByPXt9LGcoIm5leHQiKSxnKCJ0aHJvdyIpLGcoInJldHVybiIpLHJbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHI7ZnVuY3Rpb24gZyhhKXtJW2FdJiYoclthXT1mdW5jdGlvbihDKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oUSxmKXtpLnB1c2goW2EsQyxRLGZdKT4xfHxuKGEsQyl9KX0pfWZ1bmN0aW9uIG4oYSxDKXt0cnl7RShJW2FdKEMpKX1jYXRjaChRKXtjKGlbMF1bM10sUSl9fWZ1bmN0aW9uIEUoYSl7YS52YWx1ZSBpbnN0YW5jZW9mIG5BP1Byb21pc2UucmVzb2x2ZShhLnZhbHVlLnYpLnRoZW4obyxCKTpjKGlbMF1bMl0sYSl9ZnVuY3Rpb24gbyhhKXtuKCJuZXh0IixhKX1mdW5jdGlvbiBCKGEpe24oInRocm93IixhKX1mdW5jdGlvbiBjKGEsQyl7YShDKSxpLnNoaWZ0KCksaS5sZW5ndGgmJm4oaVswXVswXSxpWzBdWzFdKX19LEtJPWZ1bmN0aW9uKEEpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgZT1BW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSx0O3JldHVybiBlP2UuY2FsbChBKTooQT10eXBlb2YgX192YWx1ZXM9PSJmdW5jdGlvbiI/X192YWx1ZXMoQSk6QVtTeW1ib2wuaXRlcmF0b3JdKCksdD17fSxJKCJuZXh0IiksSSgidGhyb3ciKSxJKCJyZXR1cm4iKSx0W1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0KTtmdW5jdGlvbiBJKGkpe3RbaV09QVtpXSYmZnVuY3Rpb24oZyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4sRSl7Zz1BW2ldKGcpLHIobixFLGcuZG9uZSxnLnZhbHVlKX0pfX1mdW5jdGlvbiByKGksZyxuLEUpe1Byb21pc2UucmVzb2x2ZShFKS50aGVuKGZ1bmN0aW9uKG8pe2koe3ZhbHVlOm8sZG9uZTpufSl9LGcpfX07ZnVuY3Rpb24geEkoQSl7cmV0dXJuIFRJKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKigpe2ZvcihsZXQgdD0wO3Q8T0EubGVuZ3RoO3QrKyl7bGV0IEk9T0FbdF0rIi1yZWFkLW1lc2giLHI9eWllbGQgbkEoRyhJLEEuY29uZmlnLm1lc2hJT1VybCkpO3lpZWxkIHlpZWxkIG5BKHIpfX0pfWFzeW5jIGZ1bmN0aW9uIFBJKEEsZSl7dmFyIHQsSTtpZihBLm1pbWVUeXBlJiZhZS5oYXMoQS5taW1lVHlwZSkpe2xldCBuPWFlLmdldChBLm1pbWVUeXBlKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1sZXQgcj1rQShBLmZpbGVOYW1lKTtpZihzZS5oYXMocikpe2xldCBuPXNlLmdldChyKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1mb3IobGV0IG49MDtuPE9BLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsS0koeEkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBDZT1QSTt2YXIgV0k9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIGpJKEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCB0PTA7dDxBLmxlbmd0aDt0Kyspe2xldCBJPVpJKEFbdF0pO0khPT1udWxsJiZlLnB1c2goSSl9cmV0dXJuIGV9ZnVuY3Rpb24gWkkoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgZT1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD9lPUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKGU9QSksV0kmJmUgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmV9dmFyIGF0PWpJO2Z1bmN0aW9uIF9JKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciBCZT1fSTtmdW5jdGlvbiBWSShBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgUWU9Vkk7ZnVuY3Rpb24gekkoQSl7cmV0dXJuW0EucG9pbnRzLEEudmVydGljZXMsQS5saW5lcyxBLnBvbHlnb25zLEEudHJpYW5nbGVTdHJpcHMsQS5wb2ludERhdGEsQS5jZWxsRGF0YV19dmFyIHN0PXpJO2FzeW5jIGZ1bmN0aW9uIFhJKEEsZSx0LEkpe2xldCByPXooQSxlLHQsSSksaT1bXTtyZXR1cm4gci5vdXRwdXRzJiZyLm91dHB1dHMuZm9yRWFjaChmdW5jdGlvbihnKXtpZihnLnR5cGU9PT11LkJpbmFyeVN0cmVhbXx8Zy50eXBlPT09dS5CaW5hcnlGaWxlKXtsZXQgbj1nLmRhdGE7aS5wdXNoKG4pfWVsc2UgaWYoZy50eXBlPT09dS5JbWFnZSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5CZShuKSl9ZWxzZSBpZihnLnR5cGU9PT11Lk1lc2gpe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uUWUobikpfWVsc2UgaWYoZy50eXBlPT09dS5Qb2x5RGF0YSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5zdChuKSl9ZWxzZSBpZihnLnR5cGU9PT1TLkJpbmFyeSl7bGV0IG49Zy5kYXRhO2kucHVzaChuKX1lbHNlIGlmKGcudHlwZT09PVMuSW1hZ2Upe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uQmUobikpfWVsc2UgaWYoZy50eXBlPT09Uy5NZXNoKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLlFlKG4pKX19KSxIQShyLGF0KGkpKX12YXIgWT1YSTt2YXIgdkk9e21lc2hUb1BvbHlEYXRhOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkpe2xldCByPWF3YWl0IEcoIm1lc2gtdG8tcG9seWRhdGEiLEEubWVzaElPVXJsKTtyZXR1cm4gWShyLGUsdCxJKX0scG9seURhdGFUb01lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSl7bGV0IHI9YXdhaXQgRygicG9seWRhdGEtdG8tbWVzaCIsQS5tZXNoSU9VcmwpO3JldHVybiBZKHIsZSx0LEkpfSxyZWFkSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi1yZWFkLWltYWdlIik7cmV0dXJuIFkoZyxJLHIsaSl9LHdyaXRlSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1pbWFnZSIpO3JldHVybiBZKGcsSSxyLGkpfSxyZWFkTWVzaDphc3luYyBmdW5jdGlvbihBLGUsdCxJLHIsaSl7bGV0IGc9YXdhaXQgQ2Uoe2ZpbGVOYW1lOnQsbWltZVR5cGU6ZSxjb25maWc6QSxhcmdzOkksb3V0cHV0czpyLGlucHV0czppfSwiLXJlYWQtbWVzaCIpO3JldHVybiBZKGcsSSxyLGkpfSx3cml0ZU1lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IENlKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1tZXNoIik7cmV0dXJuIFkoZyxJLHIsaSl9LHJ1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz10eXBlb2YgQVt0XT4idSI/dDpBW3RdLG49YXdhaXQgRyhlLGcpO3JldHVybiBZKG4sSSxyLGkpfX07RUEodkkpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7cHIodXIpO2V4cG9ydHtIQSBhcyBiaW9SYWRSZWFkSW1hZ2UsWUEgYXMgYmlvUmFkV3JpdGVJbWFnZSxPQSBhcyBibXBSZWFkSW1hZ2UsVUEgYXMgYm1wV3JpdGVJbWFnZSx0dCBhcyBmZGZSZWFkSW1hZ2UsZW8gYXMgZmRmV3JpdGVJbWFnZSxYQSBhcyBnZGNtUmVhZEltYWdlLCRBIGFzIGdkY21Xcml0ZUltYWdlLF9BIGFzIGdlNFJlYWRJbWFnZSx6QSBhcyBnZTRXcml0ZUltYWdlLFZBIGFzIGdlNVJlYWRJbWFnZSxaQSBhcyBnZTVXcml0ZUltYWdlLEtBIGFzIGdlQWR3UmVhZEltYWdlLGpBIGFzIGdlQWR3V3JpdGVJbWFnZSx5IGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLEMgYXMgZ2V0UGlwZWxpbmVzQmFzZVVybCxxQSBhcyBnaXBsUmVhZEltYWdlLHZBIGFzIGdpcGxXcml0ZUltYWdlLFNBIGFzIGhkZjVSZWFkSW1hZ2UsV0EgYXMgaGRmNVdyaXRlSW1hZ2Usd0EgYXMganBlZ1JlYWRJbWFnZSxSQSBhcyBqcGVnV3JpdGVJbWFnZSxUQSBhcyBsc21SZWFkSW1hZ2UsSkEgYXMgbHNtV3JpdGVJbWFnZSxCQSBhcyBtZXRhUmVhZEltYWdlLENBIGFzIG1ldGFXcml0ZUltYWdlLExBIGFzIG1naFJlYWRJbWFnZSxNQSBhcyBtZ2hXcml0ZUltYWdlLE5BIGFzIG1pbmNSZWFkSW1hZ2UsUEEgYXMgbWluY1dyaXRlSW1hZ2UseEEgYXMgbXJjUmVhZEltYWdlLEdBIGFzIG1yY1dyaXRlSW1hZ2UsUUEgYXMgbmlmdGlSZWFkSW1hZ2UsaEEgYXMgbmlmdGlXcml0ZUltYWdlLGJBIGFzIG5ycmRSZWFkSW1hZ2Usa0EgYXMgbnJyZFdyaXRlSW1hZ2UsY0EgYXMgcG5nUmVhZEltYWdlLGRBIGFzIHBuZ1dyaXRlSW1hZ2UsbnQgYXMgcmVhZEltYWdlLFZhIGFzIHJlYWRJbWFnZUZpbGVTZXJpZXMsZXQgYXMgc2NhbmNvUmVhZEltYWdlLEF0IGFzIHNjYW5jb1dyaXRlSW1hZ2UscHIgYXMgc2V0UGlwZWxpbmVXb3JrZXJVcmwscGwgYXMgc2V0UGlwZWxpbmVzQmFzZVVybCx5QSBhcyB0aWZmUmVhZEltYWdlLEVBIGFzIHRpZmZXcml0ZUltYWdlLERBIGFzIHZ0a1JlYWRJbWFnZSxGQSBhcyB2dGtXcml0ZUltYWdlLHJ0IGFzIHdhc21SZWFkSW1hZ2UsaXQgYXMgd2FzbVdyaXRlSW1hZ2UsYXQgYXMgd2FzbVpzdGRSZWFkSW1hZ2Usb3QgYXMgd2FzbVpzdGRXcml0ZUltYWdlLFhhIGFzIHdyaXRlSW1hZ2V9OwovKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOgoKY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczoKICAoKioKICAgKiBAbGljZW5zZQogICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMKICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMAogICAqKQoqLwo=""" default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_read_image_async.py new file mode 100644 index 000000000..2dfb3f07c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def lsm_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.lsmReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_write_image_async.py new file mode 100644 index 000000000..9e1821d95 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/lsm_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def lsm_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.lsmWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_read_image_async.py new file mode 100644 index 000000000..5e0834c8e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def meta_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.metaReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_write_image_async.py new file mode 100644 index 000000000..109d63c06 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/meta_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def meta_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.metaWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_read_image_async.py new file mode 100644 index 000000000..2538e0b5e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def mgh_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.mghReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_write_image_async.py new file mode 100644 index 000000000..e5e58026e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mgh_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def mgh_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.mghWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_read_image_async.py new file mode 100644 index 000000000..b22040ff4 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def mrc_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.mrcReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_write_image_async.py new file mode 100644 index 000000000..f796663af --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/mrc_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def mrc_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.mrcWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_read_image_async.py new file mode 100644 index 000000000..1992790f7 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def nifti_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.niftiReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_write_image_async.py new file mode 100644 index 000000000..2b91e95d9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nifti_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def nifti_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.niftiWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_read_image_async.py new file mode 100644 index 000000000..bed24f969 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def nrrd_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.nrrdReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_write_image_async.py new file mode 100644 index 000000000..b135a0c8e --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/nrrd_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def nrrd_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.nrrdWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_read_image_async.py new file mode 100644 index 000000000..bf004609a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def png_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.pngReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_write_image_async.py new file mode 100644 index 000000000..adbfb115f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/png_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def png_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.pngWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/read_image_async.py new file mode 100644 index 000000000..7f5461e62 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/read_image_async.py @@ -0,0 +1,106 @@ +import os +from typing import Optional, Union +from pathlib import Path + +from itkwasm import ( + Image, + PixelTypes, + IntTypes, + FloatTypes, + BinaryFile, + cast_image, +) + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) + +from .extension_to_image_io import extension_to_image_io +from .image_io_index import image_io_index + +async def read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :param pixel_type: Pixel type to cast to. + :type pixel_Type: Optional[PixelTypes] + + :param component_type: Component type to cast to. + :type component_type: Optional[Union[IntTypes, FloatTypes]] + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + extension = ''.join(Path(serialized_image).suffixes) + + io = None + if extension in extension_to_image_io: + func = f"{extension_to_image_io[extension]}ReadImage" + io = getattr(js_module, func) + else: + for ioname in image_io_index: + func = f"{ioname}ReadImage" + io = getattr(js_module, func) + outputs = await io(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + outputs_object_map = outputs.as_object_map() + web_worker = outputs_object_map['webWorker'] + js_resources.web_worker = web_worker + could_read = to_py(outputs_object_map['couldRead']) + if could_read: + image = to_py(outputs_object_map['image']) + if pixel_type or component_type: + image = cast_image(image, pixel_type=pixel_type, component_type=component_type) + return image + + if io is None: + raise RuntimeError(f"Could not find an image reader for {extension}") + + outputs = await js_module.readImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + outputs = await io(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + outputs_object_map = outputs.as_object_map() + web_worker = outputs_object_map['webWorker'] + could_read = to_py(outputs_object_map['couldRead']) + + if not could_read: + raise RuntimeError(f"Could not read {serialized_image}") + + js_resources.web_worker = web_worker + + image = to_py(outputs_object_map['image']) + + if pixel_type or component_type: + image = cast_image(image, pixel_type=pixel_type, component_type=component_type) + return image + +async def imread_async( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + return await read_image_async(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type) + +imread_async.__doc__ = f"""{read_image_async.__doc__} + Alias for read_image_async. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_read_image_async.py new file mode 100644 index 000000000..a1601ec0c --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def scanco_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.scancoReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_write_image_async.py new file mode 100644 index 000000000..ab00d9c3b --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/scanco_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def scanco_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.scancoWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_read_image_async.py new file mode 100644 index 000000000..0dfb53c72 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def tiff_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.tiffReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_write_image_async.py new file mode 100644 index 000000000..db5070446 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/tiff_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def tiff_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.tiffWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_read_image_async.py new file mode 100644 index 000000000..df96819c4 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def vtk_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.vtkReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_write_image_async.py new file mode 100644 index 000000000..5066add67 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/vtk_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def vtk_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.vtkWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_read_image_async.py new file mode 100644 index 000000000..5509121c9 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def wasm_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.wasmReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_write_image_async.py new file mode 100644 index 000000000..5d0c8be6d --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def wasm_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.wasmWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_read_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_read_image_async.py new file mode 100644 index 000000000..5cf370ae3 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_read_image_async.py @@ -0,0 +1,60 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + BinaryFile, + Image, +) + +async def wasm_zstd_read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, +) -> Tuple[Any, Image]: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :return: Whether the input could be read. If false, the output image is not valid. + :rtype: Any + + :return: Output image + :rtype: Image + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + + outputs = await js_module.wasmZstdReadImage(web_worker, to_js(BinaryFile(serialized_image)), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_write_image_async.py new file mode 100644 index 000000000..245739fa3 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/wasm_zstd_write_image_async.py @@ -0,0 +1,67 @@ +# Generated file. To retain edits, remove this comment. + +from pathlib import Path +import os +from typing import Dict, Tuple, Optional, List, Any + +from .js_package import js_package + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) +from itkwasm import ( + InterfaceTypes, + Image, + BinaryFile, +) + +async def wasm_zstd_write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> Tuple[Any]: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :return: Whether the input could be written. If false, the output image is not valid. + :rtype: Any + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + outputs = await js_module.wasmZstdWriteImage(web_worker, to_js(image), to_js(serialized_image), **kwargs) + + output_web_worker = None + output_list = [] + outputs_object_map = outputs.as_object_map() + for output_name in outputs.object_keys(): + if output_name == 'webWorker': + output_web_worker = outputs_object_map[output_name] + else: + output_list.append(to_py(outputs_object_map[output_name])) + + js_resources.web_worker = output_web_worker + + if len(output_list) == 1: + return output_list[0] + return tuple(output_list) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/write_image_async.py new file mode 100644 index 000000000..9bdaa717f --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/write_image_async.py @@ -0,0 +1,95 @@ +import os +import importlib +from pathlib import Path +from typing import Optional, Union + +from itkwasm import Image, PixelTypes, IntTypes, FloatTypes, BinaryFile + +from itkwasm.pyodide import ( + to_js, + to_py, + js_resources +) + +from .js_package import js_package + +from .extension_to_image_io import extension_to_image_io +from .image_io_index import image_io_index + +async def write_image_async( + image: Image, + serialized_image: os.PathLike, + information_only: bool = False, + use_compression: bool = False, +) -> None: + """Write an itk-wasm Image to an image file format. + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + """ + js_module = await js_package.js_module + web_worker = js_resources.web_worker + + kwargs = {} + if information_only: + kwargs["informationOnly"] = to_js(information_only) + if use_compression: + kwargs["useCompression"] = to_js(use_compression) + + extension = ''.join(Path(serialized_image).suffixes) + + io = None + if extension in extension_to_image_io: + func = f"{extension_to_image_io[extension]}WriteImage" + io = getattr(js_module, func) + else: + for ioname in image_io_index: + func = f"{ioname}WriteImage" + io = getattr(js_module, func) + outputs = await io(web_worker, to_js(image), to_js(serialized_image), **kwargs) + outputs_object_map = outputs.as_object_map() + web_worker = outputs_object_map['webWorker'] + js_resources.web_worker = web_worker + could_write = to_py(outputs_object_map['couldWrite']) + if could_write: + to_py(outputs_object_map['serializedImage']) + return + + if io is None: + raise RuntimeError(f"Could not find an image writer for {extension}") + + io = getattr(js_module, func) + outputs = await io(web_worker, to_js(image), to_js(serialized_image), **kwargs) + outputs_object_map = outputs.as_object_map() + web_worker = outputs_object_map['webWorker'] + js_resources.web_worker = web_worker + could_write = to_py(outputs_object_map['couldWrite']) + + if not could_write: + raise RuntimeError(f"Could not write {serialized_image}") + + to_py(outputs_object_map['serializedImage']) + +async def imwrite_async( + image: Image, + serialized_image: os.PathLike, + information_only: bool = False, + use_compression: bool = False, +) -> None: + return write_image_async(image, serialized_image, information_only=information_only, use_compression=use_compression) + +imwrite_async.__doc__ = f"""{write_image_async.__doc__} + Alias for write_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml b/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml index 8f4db83bf..d9ecee899 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml +++ b/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml @@ -32,7 +32,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", ] [tool.hatch.version] diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py new file mode 100644 index 000000000..d6c91f8b2 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py @@ -0,0 +1,29 @@ +import pytest +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide + +from itkwasm_image_io_emscripten import __version__ as test_package_version + +@pytest.fixture +def package_wheel(): + return f"itkwasm_image_io_emscripten-{test_package_version}-py3-none-any.whl" + +@pytest.fixture +def input_data(): + from pathlib import Path + input_base_path = Path('..', '..', 'test', 'data') + test_files = [ + Path('input') / 'cthead1.png', + Path('input') / 'biorad.pic', + Path('input') / 'brainweb165a10f17.mha', + ] + data = {} + for f in test_files: + with open(input_base_path / f, 'rb') as fp: + print(str(f.name)) + data[str(f.name)] = fp.read() + return data \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/test_bio_rad_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_bio_rad_async.py new file mode 100644 index 000000000..484d69076 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_bio_rad_async.py @@ -0,0 +1,57 @@ +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide +from .fixtures import package_wheel, input_data + +@run_in_pyodide(packages=['micropip']) +async def test_bio_rad_async(selenium, package_wheel, input_data): + import micropip + await micropip.install(package_wheel) + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) + + from pathlib import Path + + from itkwasm_image_io_emscripten import bio_rad_read_image_async, bio_rad_write_image_async + + def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 0.06000000238418579 + assert image.spacing[1] == 0.06000000238418579 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 768 + assert image.size[1] == 512 + assert image.data.shape[1] == 768 + assert image.data.shape[0] == 512 + assert image.data.ravel()[1000] == 27 + + test_file_path = 'biorad.pic' + write_input_data_to_fs(input_data, test_file_path) + + assert Path(test_file_path).exists() + + could_read, image = await bio_rad_read_image_async(test_file_path) + assert could_read + verify_image(image) + + test_output_file_path = 'biorad_out.pic' + + use_compression = False + could_write = await bio_rad_write_image_async(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = await bio_rad_read_image_async(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/test_metaimage_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_metaimage_async.py new file mode 100644 index 000000000..e75454e52 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_metaimage_async.py @@ -0,0 +1,65 @@ +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide +from .fixtures import package_wheel, input_data + +@run_in_pyodide(packages=['micropip']) +async def test_metaimage_async(selenium, package_wheel, input_data): + import micropip + await micropip.install(package_wheel) + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) + + from pathlib import Path + + from itkwasm_image_io_emscripten import meta_read_image_async, meta_write_image_async + + test_input_file_path = 'brainweb165a10f17.mha' + test_output_file_path = 'meta-image-test-brainweb165a10f17.mha' + + def verify_image(image): + assert image.imageType.dimension == 3 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.origin[2] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.spacing[2] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[0, 2] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.direction[1, 2] == 0.0 + assert image.direction[2, 0] == 0.0 + assert image.direction[2, 1] == 0.0 + assert image.direction[2, 2] == 1.0 + assert image.size[0] == 181 + assert image.size[1] == 217 + assert image.size[2] == 180 + assert image.data.ravel()[0] == 5 + assert image.data.ravel()[1] == 8 + assert image.data.ravel()[2] == 2 + + write_input_data_to_fs(input_data, test_input_file_path) + + assert Path(test_input_file_path).exists() + + could_read, image = await meta_read_image_async(test_input_file_path) + assert could_read + verify_image(image) + + use_compression = False + could_write = await meta_write_image_async(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = await meta_read_image_async(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/test_read_write_image_async.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_read_write_image_async.py new file mode 100644 index 000000000..3a750f814 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io-emscripten/test/test_read_write_image_async.py @@ -0,0 +1,53 @@ +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide +from .fixtures import package_wheel, input_data + +@run_in_pyodide(packages=['micropip']) +async def test_read_write_image_async(selenium, package_wheel, input_data): + import micropip + await micropip.install(package_wheel) + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) + + from pathlib import Path + + from itkwasm_image_io_emscripten import read_image_async, write_image_async + + test_input_file_path = "cthead1.png" + test_output_file_path = "read-write-cthead1.png" + + def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 3 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + + write_input_data_to_fs(input_data, test_input_file_path) + + assert Path(test_input_file_path).exists() + + image = await read_image_async(test_input_file_path) + verify_image(image) + + use_compression = False + await write_image_async(image, test_output_file_path, use_compression=use_compression) + + image = await read_image_async(test_output_file_path) + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py index de339c7c0..efe1f0497 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/image_io_index.py @@ -12,14 +12,14 @@ 'mrc', 'lsm', 'mgh', - 'bio_rad', + 'bioRad', 'gipl', - 'ge_adw', + 'geAdw', 'ge4', 'ge5', 'gdcm', 'scanco', 'wasm', - 'wasm_zstd', + 'wasmZstd', ] diff --git a/packages/image-io/typescript/build/rollup.browser.config.js b/packages/image-io/typescript/build/rollup.browser.config.js deleted file mode 100644 index 98ec279b6..000000000 --- a/packages/image-io/typescript/build/rollup.browser.config.js +++ /dev/null @@ -1,49 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import nodePolyfills from 'rollup-plugin-polyfill-node' -import ignore from 'rollup-plugin-ignore' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import json from '@rollup/plugin-json' -import path from 'path' -import OMT from "@surma/rollup-plugin-off-main-thread" - -const omtCustom = OMT() -omtCustom.resolveImportMeta = () => { - return 'import.meta.url' -} - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index.ts', - output: [ - { - dir: `./dist`, - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - onwarn: function onwarn(warning, warn) { - if (warning.code === 'THIS_IS_UNDEFINED') return; - if (warning.message.includes('Very few browsers support ES modules in Workers.')) return; - console.log('onwarn', warning) - warn(warning); - }, - plugins: [ - ignore(['crypto']), - nodeResolve({ - preferBuiltins: false, - browser: true, - }), - commonjs({ - transformMixedEsModules: true - }), - nodePolyfills(), - typescript(), - json(), - omtCustom, - ] -} diff --git a/packages/image-io/typescript/build/rollup.node.config.js b/packages/image-io/typescript/build/rollup.node.config.js deleted file mode 100644 index 57d19955d..000000000 --- a/packages/image-io/typescript/build/rollup.node.config.js +++ /dev/null @@ -1,36 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import path from 'path' - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index-node.ts', - output: [ - { - dir: './dist', - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - onwarn: function onwarn(warning, warn) { - if (warning.code === 'THIS_IS_UNDEFINED') return; - warn(warning); - }, - plugins: [ - commonjs({ - transformMixedEsModules: true - }), - nodeResolve({ - preferBuiltins: true, - browser: false, - }), - typescript(), - json(), - ], -} diff --git a/packages/image-io/typescript/build/vite-rollup-watch.config.js b/packages/image-io/typescript/build/vite-rollup-watch.config.js new file mode 100644 index 000000000..8d52ea773 --- /dev/null +++ b/packages/image-io/typescript/build/vite-rollup-watch.config.js @@ -0,0 +1,23 @@ +import { generateConfig } from './vite.config' + +export default defineConfig(({ mode }) => { + const config: UserConfig = generateConfig({ mode }) + + config.preview = { + port: 5004, + } + + config.build = { + // Enable Rollup watcher @see https://vitejs.dev/config/#build-watch + watch: {}, + + // Opt for the fastest build + target: 'esnext', + minify: false, + rollupOptions: { ...config.build.rollupOptions, treeshake: false }, + + outDir: './dist-rollup/', + } + + return config +}) \ No newline at end of file diff --git a/packages/image-io/typescript/build/vite.config.js b/packages/image-io/typescript/build/vite.config.js index 7ef77ee3a..699cddda9 100644 --- a/packages/image-io/typescript/build/vite.config.js +++ b/packages/image-io/typescript/build/vite.config.js @@ -15,6 +15,9 @@ export function generateConfig() { worker: { format: 'es' }, + optimizeDeps: { + exclude: ['itk-wasm'] + }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory viteStaticCopy({ diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json index 19a893c84..c5aacc7f7 100644 --- a/packages/image-io/typescript/package.json +++ b/packages/image-io/typescript/package.json @@ -24,13 +24,13 @@ "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:browser:webWorkers && npm run build:browser:workerEmbedded && npm run build:demo", - "build:browser:webWorkers": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/", - "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/image-io-worker-embedded.js ./src/index-worker-embedded.ts", + "build": "npm run build:tsc && npm run build:browser:workerEmbedded && npm run build:browser:workerEmbeddedMin && npm run build:demo", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build:browser:workerEmbeddedMin": "esbuild --minify --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.min.js ./src/index-worker-embedded.min.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build", - "rollup:start": "npm run copyShoelaceAssets && concurrently npm:rollup:dev npm:rollup:preview", + "rollup:start": "npm run copyShoelaceAssets && npm run build:demo && concurrently npm:rollup:dev npm:rollup:preview", "rollup:dev": "vite build --config build/vite-rollup-watch.config.ts", "rollup:preview": "vite preview --config build/vite-rollup-watch.config.ts" }, @@ -43,7 +43,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.152" + "itk-wasm": "^1.0.0-b.154" }, "devDependencies": { "@shoelace-style/shoelace": "^2.5.2", @@ -55,7 +55,7 @@ "shx": "^0.3.4", "start-server-and-test": "^2.0.1", "typescript": "^5.0.4", - "vite": "^4.4.11", + "vite": "^4.5.0", "vite-plugin-static-copy": "^0.17.0" }, "repository": { diff --git a/packages/image-io/typescript/pnpm-lock.yaml b/packages/image-io/typescript/pnpm-lock.yaml new file mode 100644 index 000000000..ab5018a29 --- /dev/null +++ b/packages/image-io/typescript/pnpm-lock.yaml @@ -0,0 +1,3039 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + itk-wasm: + specifier: ^1.0.0-b.154 + version: 1.0.0-b.154 + +devDependencies: + '@shoelace-style/shoelace': + specifier: ^2.5.2 + version: 2.11.2(@types/react@18.2.34) + '@types/node': + specifier: ^20.2.5 + version: 20.8.10 + ava: + specifier: ^5.3.1 + version: 5.3.1 + concurrently: + specifier: ^8.2.1 + version: 8.2.2 + cypress: + specifier: ^13.3.0 + version: 13.4.0 + esbuild: + specifier: ^0.19.5 + version: 0.19.5 + shx: + specifier: ^0.3.4 + version: 0.3.4 + start-server-and-test: + specifier: ^2.0.1 + version: 2.0.1 + typescript: + specifier: ^5.0.4 + version: 5.2.2 + vite: + specifier: ^4.5.0 + version: 4.5.0(@types/node@20.8.10) + vite-plugin-static-copy: + specifier: ^0.17.0 + version: 0.17.0(vite@4.5.0) + +packages: + + /@babel/runtime@7.23.2: + resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + + /@colors/colors@1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@ctrl/tinycolor@4.0.2: + resolution: {integrity: sha512-fKQinXE9pJ83J1n+C3rDl2xNLJwfoYNvXLRy5cYZA9hBJJw2q+sbb/AOSNKmLxnTWyNTmy4994dueSwP4opi5g==} + engines: {node: '>=14'} + dev: true + + /@cypress/request@3.0.1: + resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==} + engines: {node: '>= 6'} + dependencies: + aws-sign2: 0.7.0 + aws4: 1.12.0 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + http-signature: 1.3.6 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + performance-now: 2.1.0 + qs: 6.10.4 + safe-buffer: 5.2.1 + tough-cookie: 4.1.3 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + dev: true + + /@cypress/xvfb@1.2.4(supports-color@8.1.1): + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + dependencies: + debug: 3.2.7(supports-color@8.1.1) + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64@0.19.5: + resolution: {integrity: sha512-5d1OkoJxnYQfmC+Zd8NBFjkhyCNYwM4n9ODrycTFY6Jk1IGiZ+tjVJDDSwDt77nK+tfpGP4T50iMtVi4dEGzhQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.19.5: + resolution: {integrity: sha512-bhvbzWFF3CwMs5tbjf3ObfGqbl/17ict2/uwOSfr3wmxDE6VdS2GqY/FuzIPe0q0bdhj65zQsvqfArI9MY6+AA==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.19.5: + resolution: {integrity: sha512-9t+28jHGL7uBdkBjL90QFxe7DVA+KGqWlHCF8ChTKyaKO//VLuoBricQCgwhOjA1/qOczsw843Fy4cbs4H3DVA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.19.5: + resolution: {integrity: sha512-mvXGcKqqIqyKoxq26qEDPHJuBYUA5KizJncKOAf9eJQez+L9O+KfvNFu6nl7SCZ/gFb2QPaRqqmG0doSWlgkqw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.19.5: + resolution: {integrity: sha512-Ly8cn6fGLNet19s0X4unjcniX24I0RqjPv+kurpXabZYSXGM4Pwpmf85WHJN3lAgB8GSth7s5A0r856S+4DyiA==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.19.5: + resolution: {integrity: sha512-GGDNnPWTmWE+DMchq1W8Sd0mUkL+APvJg3b11klSGUDvRXh70JqLAO56tubmq1s2cgpVCSKYywEiKBfju8JztQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.19.5: + resolution: {integrity: sha512-1CCwDHnSSoA0HNwdfoNY0jLfJpd7ygaLAp5EHFos3VWJCRX9DMwWODf96s9TSse39Br7oOTLryRVmBoFwXbuuQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.19.5: + resolution: {integrity: sha512-o3vYippBmSrjjQUCEEiTZ2l+4yC0pVJD/Dl57WfPwwlvFkrxoSO7rmBZFii6kQB3Wrn/6GwJUPLU5t52eq2meA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.19.5: + resolution: {integrity: sha512-lrWXLY/vJBzCPC51QN0HM71uWgIEpGSjSZZADQhq7DKhPcI6NH1IdzjfHkDQws2oNpJKpR13kv7/pFHBbDQDwQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.19.5: + resolution: {integrity: sha512-MkjHXS03AXAkNp1KKkhSKPOCYztRtK+KXDNkBa6P78F8Bw0ynknCSClO/ztGszILZtyO/lVKpa7MolbBZ6oJtQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.19.5: + resolution: {integrity: sha512-42GwZMm5oYOD/JHqHska3Jg0r+XFb/fdZRX+WjADm3nLWLcIsN27YKtqxzQmGNJgu0AyXg4HtcSK9HuOk3v1Dw==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.19.5: + resolution: {integrity: sha512-kcjndCSMitUuPJobWCnwQ9lLjiLZUR3QLQmlgaBfMX23UEa7ZOrtufnRds+6WZtIS9HdTXqND4yH8NLoVVIkcg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.19.5: + resolution: {integrity: sha512-yJAxJfHVm0ZbsiljbtFFP1BQKLc8kUF6+17tjQ78QjqjAQDnhULWiTA6u0FCDmYT1oOKS9PzZ2z0aBI+Mcyj7Q==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.19.5: + resolution: {integrity: sha512-5u8cIR/t3gaD6ad3wNt1MNRstAZO+aNyBxu2We8X31bA8XUNyamTVQwLDA1SLoPCUehNCymhBhK3Qim1433Zag==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.19.5: + resolution: {integrity: sha512-Z6JrMyEw/EmZBD/OFEFpb+gao9xJ59ATsoTNlj39jVBbXqoZm4Xntu6wVmGPB/OATi1uk/DB+yeDPv2E8PqZGw==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.19.5: + resolution: {integrity: sha512-psagl+2RlK1z8zWZOmVdImisMtrUxvwereIdyJTmtmHahJTKb64pAcqoPlx6CewPdvGvUKe2Jw+0Z/0qhSbG1A==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.19.5: + resolution: {integrity: sha512-kL2l+xScnAy/E/3119OggX8SrWyBEcqAh8aOY1gr4gPvw76la2GlD4Ymf832UCVbmuWeTf2adkZDK+h0Z/fB4g==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.19.5: + resolution: {integrity: sha512-sPOfhtzFufQfTBgRnE1DIJjzsXukKSvZxloZbkJDG383q0awVAq600pc1nfqBcl0ice/WN9p4qLc39WhBShRTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.19.5: + resolution: {integrity: sha512-dGZkBXaafuKLpDSjKcB0ax0FL36YXCvJNnztjKV+6CO82tTYVDSH2lifitJ29jxRMoUhgkg9a+VA/B03WK5lcg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.19.5: + resolution: {integrity: sha512-dWVjD9y03ilhdRQ6Xig1NWNgfLtf2o/STKTS+eZuF90fI2BhbwD6WlaiCGKptlqXlURVB5AUOxUj09LuwKGDTg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.19.5: + resolution: {integrity: sha512-4liggWIA4oDgUxqpZwrDhmEfAH4d0iljanDOK7AnVU89T6CzHon/ony8C5LeOdfgx60x5cnQJFZwEydVlYx4iw==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.19.5: + resolution: {integrity: sha512-czTrygUsB/jlM8qEW5MD8bgYU2Xg14lo6kBDXW6HdxKjh8M5PzETGiSHaz9MtbXBYDloHNUAUW2tMiKW4KM9Mw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@floating-ui/core@1.5.0: + resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} + dependencies: + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/dom@1.5.3: + resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} + dependencies: + '@floating-ui/core': 1.5.0 + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/utils@0.1.6: + resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + dev: true + + /@hapi/hoek@9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: true + + /@hapi/topo@5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@lit-labs/ssr-dom-shim@1.1.2: + resolution: {integrity: sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==} + dev: true + + /@lit/react@1.0.1(@types/react@18.2.34): + resolution: {integrity: sha512-io4yIAl9ZFY5coI2ix+nSly4rmEKLFyZM66mxOr9xvxDqwtjdVU/g6Tchb7bo+A23+5Uu/1RZpLCpvHLCGi0rw==} + peerDependencies: + '@types/react': 17 || 18 + dependencies: + '@types/react': 18.2.34 + dev: true + + /@lit/reactive-element@2.0.1: + resolution: {integrity: sha512-eu50SQXHRthFwWJMp0oAFg95Rvm6MTPjxSXWuvAu7It90WVFLFpNBoIno7XOXSDvVgTrtKnUV4OLJqys2Svn4g==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.1.2 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@shoelace-style/animations@1.1.0: + resolution: {integrity: sha512-Be+cahtZyI2dPKRm8EZSx3YJQ+jLvEcn3xzRP7tM4tqBnvd/eW/64Xh0iOf0t2w5P8iJKfdBbpVNE9naCaOf2g==} + dev: true + + /@shoelace-style/localize@3.1.2: + resolution: {integrity: sha512-Hf45HeO+vdQblabpyZOTxJ4ZeZsmIUYXXPmoYrrR4OJ5OKxL+bhMz5mK8JXgl7HsoEowfz7+e248UGi861de9Q==} + dev: true + + /@shoelace-style/shoelace@2.11.2(@types/react@18.2.34): + resolution: {integrity: sha512-V94PTZ3CKcRH7NozDIEK5gMG3yeCZhF/3jCpKZ7Wexpf9kOqIRaMGoW3omq21I8NRefNLEknkV9Q392JIZLjBA==} + engines: {node: '>=14.17.0'} + dependencies: + '@ctrl/tinycolor': 4.0.2 + '@floating-ui/dom': 1.5.3 + '@lit/react': 1.0.1(@types/react@18.2.34) + '@shoelace-style/animations': 1.1.0 + '@shoelace-style/localize': 3.1.2 + composed-offset-position: 0.0.4 + lit: 3.0.2 + qr-creator: 1.0.0 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@sideway/address@4.1.4: + resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@sideway/formula@3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: true + + /@sideway/pinpoint@2.0.0: + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + dev: true + + /@thewtex/zstddec@0.2.0: + resolution: {integrity: sha512-lIS+smrfa48WGlDVQSQSm0jBnwVp5XmfGJWU9q0J0fRFY9ohzK4s27Zg2SFMb1NWMp9RiANAdK+/q86EBGWR1Q==} + dev: false + + /@types/emscripten@1.39.9: + resolution: {integrity: sha512-ILdWj4XYtNOqxJaW22NEQx2gJsLfV5ncxYhhGX1a1H1lXl2Ta0gUz7QOnOoF1xQbJwWDjImi8gXN9mKdIf6n9g==} + dev: false + + /@types/node@18.18.8: + resolution: {integrity: sha512-OLGBaaK5V3VRBS1bAkMVP2/W9B+H8meUfl866OrMNQqt7wDgdpWPp5o6gmIc9pB+lIQHSq4ZL8ypeH1vPxcPaQ==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/node@20.8.10: + resolution: {integrity: sha512-TlgT8JntpcbmKUFzjhsyhGfP2fsiz1Mv56im6enJ905xG1DAYesxJaeSbGqQmAw8OWPdhyJGhGSQGKRNJ45u9w==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/prop-types@15.7.9: + resolution: {integrity: sha512-n1yyPsugYNSmHgxDFjicaI2+gCNjsBck8UX9kuofAKlc0h1bL+20oSF72KeNaW2DUlesbEVCFgyV2dPGTiY42g==} + dev: true + + /@types/react@18.2.34: + resolution: {integrity: sha512-U6eW/alrRk37FU/MS2RYMjx0Va2JGIVXELTODaTIYgvWGCV4Y4TfTUzG8DdmpDNIT0Xpj/R7GfyHOJJrDttcvg==} + dependencies: + '@types/prop-types': 15.7.9 + '@types/scheduler': 0.16.5 + csstype: 3.1.2 + dev: true + + /@types/scheduler@0.16.5: + resolution: {integrity: sha512-s/FPdYRmZR8SjLWGMCuax7r3qCWQw9QKHzXVukAuuIJkXkDRwp+Pu5LMIVFi0Fxbav35WURicYr8u1QsoybnQw==} + dev: true + + /@types/sinonjs__fake-timers@8.1.1: + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + dev: true + + /@types/sizzle@2.3.5: + resolution: {integrity: sha512-tAe4Q+OLFOA/AMD+0lq8ovp8t3ysxAOeaScnfNdZpUxaGl51ZMDEITxkvFl1STudQ58mz6gzVGl9VhMKhwRnZQ==} + dev: true + + /@types/trusted-types@2.0.5: + resolution: {integrity: sha512-I3pkr8j/6tmQtKV/ZzHtuaqYSQvyjGRKH4go60Rr0IDLlFxuRT5V32uvB1mecM5G1EVAUyF/4r4QZ1GHgz+mxA==} + dev: true + + /@types/yauzl@2.10.2: + resolution: {integrity: sha512-Km7XAtUIduROw7QPgvcft0lIupeG8a8rdKL8RiSyKvlE7dYY31fEn41HVuQsRFDuROA8tA4K2UVL+WdfFmErBA==} + requiresBuild: true + dependencies: + '@types/node': 20.8.10 + dev: true + optional: true + + /acorn-walk@8.3.0: + resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + dev: true + + /arrgv@1.0.2: + resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} + engines: {node: '>=8.0.0'} + dev: true + + /arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + dev: true + + /asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + dev: true + + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + /at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /ava@5.3.1: + resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + hasBin: true + peerDependencies: + '@ava/typescript': '*' + peerDependenciesMeta: + '@ava/typescript': + optional: true + dependencies: + acorn: 8.11.2 + acorn-walk: 8.3.0 + ansi-styles: 6.2.1 + arrgv: 1.0.2 + arrify: 3.0.0 + callsites: 4.1.0 + cbor: 8.1.0 + chalk: 5.3.0 + chokidar: 3.5.3 + chunkd: 2.0.1 + ci-info: 3.9.0 + ci-parallel-vars: 1.0.1 + clean-yaml-object: 0.1.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + common-path-prefix: 3.0.0 + concordance: 5.0.4 + currently-unhandled: 0.4.1 + debug: 4.3.4(supports-color@8.1.1) + emittery: 1.0.1 + figures: 5.0.0 + globby: 13.2.2 + ignore-by-default: 2.1.0 + indent-string: 5.0.0 + is-error: 2.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + matcher: 5.0.0 + mem: 9.0.2 + ms: 2.1.3 + p-event: 5.0.1 + p-map: 5.5.0 + picomatch: 2.3.1 + pkg-conf: 4.0.0 + plur: 5.1.0 + pretty-ms: 8.0.0 + resolve-cwd: 3.0.0 + stack-utils: 2.0.6 + strip-ansi: 7.1.0 + supertap: 3.0.1 + temp-dir: 3.0.0 + write-file-atomic: 5.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + dev: true + + /aws4@1.12.0: + resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} + dev: true + + /axios@0.27.2(debug@4.3.4): + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: true + + /axios@1.6.0: + resolution: {integrity: sha512-EZ1DYihju9pwVB+jg67ogm+Tmqc6JmhamRN6I4Zt8DfZu5lbcQGw3ozH9lFejSJgs/ibaef3A9PMXPLeefFGJg==} + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + dependencies: + tweetnacl: 0.14.5 + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /blob-util@2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + dev: true + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: false + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /cachedir@2.4.0: + resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} + engines: {node: '>=6'} + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + + /callsites@4.1.0: + resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} + engines: {node: '>=12.20'} + dev: true + + /caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + dev: true + + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /check-more-types@2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /chunkd@2.0.1: + resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} + dev: true + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /ci-parallel-vars@1.0.1: + resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + dev: true + + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /clean-yaml-object@0.1.0: + resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} + engines: {node: '>=0.10.0'} + dev: true + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + dev: true + + /cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + dev: true + + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + + /comlink@4.4.1: + resolution: {integrity: sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==} + dev: false + + /commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + dev: true + + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: false + + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + + /common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + + /composed-offset-position@0.0.4: + resolution: {integrity: sha512-vMlvu1RuNegVE0YsCDSV/X4X10j56mq7PCIyOKK74FxkXzGLwhOUmdkJLSdOBOMwWycobGUMgft2lp+YgTe8hw==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.3.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.5.4 + well-known-symbols: 2.0.0 + dev: true + + /concurrently@8.2.2: + resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} + engines: {node: ^14.13.0 || >=16.0.0} + hasBin: true + dependencies: + chalk: 4.1.2 + date-fns: 2.30.0 + lodash: 4.17.21 + rxjs: 7.8.1 + shell-quote: 1.8.1 + spawn-command: 0.0.2 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + dev: true + + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true + + /currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + dependencies: + array-find-index: 1.0.2 + dev: true + + /cypress@13.4.0: + resolution: {integrity: sha512-KeWNC9xSHG/ewZURVbaQsBQg2mOKw4XhjJZFKjWbEjgZCdxpPXLpJnfq5Jns1Gvnjp6AlnIfpZfWFlDgVKXdWQ==} + engines: {node: ^16.0.0 || ^18.0.0 || >=20.0.0} + hasBin: true + requiresBuild: true + dependencies: + '@cypress/request': 3.0.1 + '@cypress/xvfb': 1.2.4(supports-color@8.1.1) + '@types/node': 18.18.8 + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.5 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.4.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.3 + commander: 6.2.1 + common-tags: 1.8.2 + dayjs: 1.11.10 + debug: 4.3.4(supports-color@8.1.1) + enquirer: 2.4.1 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1(supports-color@8.1.1) + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0(enquirer@2.4.1) + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.8 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + process: 0.11.10 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.5.4 + supports-color: 8.1.1 + tmp: 0.2.1 + untildify: 4.0.0 + yauzl: 2.10.0 + dev: true + + /dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + dev: true + + /date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.23.2 + dev: true + + /date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + dependencies: + time-zone: 1.0.0 + dev: true + + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: true + + /debug@3.2.7(supports-color@8.1.1): + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + dev: true + + /debug@4.3.4(supports-color@8.1.1): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + dev: true + + /emittery@1.0.1: + resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} + engines: {node: '>=14.16'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /esbuild@0.19.5: + resolution: {integrity: sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.19.5 + '@esbuild/android-arm64': 0.19.5 + '@esbuild/android-x64': 0.19.5 + '@esbuild/darwin-arm64': 0.19.5 + '@esbuild/darwin-x64': 0.19.5 + '@esbuild/freebsd-arm64': 0.19.5 + '@esbuild/freebsd-x64': 0.19.5 + '@esbuild/linux-arm': 0.19.5 + '@esbuild/linux-arm64': 0.19.5 + '@esbuild/linux-ia32': 0.19.5 + '@esbuild/linux-loong64': 0.19.5 + '@esbuild/linux-mips64el': 0.19.5 + '@esbuild/linux-ppc64': 0.19.5 + '@esbuild/linux-riscv64': 0.19.5 + '@esbuild/linux-s390x': 0.19.5 + '@esbuild/linux-x64': 0.19.5 + '@esbuild/netbsd-x64': 0.19.5 + '@esbuild/openbsd-x64': 0.19.5 + '@esbuild/sunos-x64': 0.19.5 + '@esbuild/win32-arm64': 0.19.5 + '@esbuild/win32-ia32': 0.19.5 + '@esbuild/win32-x64': 0.19.5 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: true + + /eventemitter2@6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + dev: true + + /execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /executable@4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + dependencies: + pify: 2.3.0 + dev: true + + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: true + + /extract-zip@2.0.1(supports-color@8.1.1): + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.2 + transitivePeerDependencies: + - supports-color + dev: true + + /extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: true + + /figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + dev: true + + /follow-redirects@1.15.3(debug@4.3.4): + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + + /forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + dev: true + + /form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: true + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: false + + /fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /getos@3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + dependencies: + async: 3.2.5 + dev: true + + /getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + dependencies: + assert-plus: 1.0.0 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + dev: false + + /global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + + /globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.1 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /http-signature@1.3.6: + resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.18.0 + dev: true + + /human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /ignore-by-default@2.1.0: + resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} + engines: {node: '>=10 <11 || >=12 <13 || >=14'} + dev: true + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + + /interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: true + + /irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.9.0 + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-error@2.2.2: + resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: true + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + dev: true + + /itk-wasm@1.0.0-b.154: + resolution: {integrity: sha512-bzwOpA4kaNNC2SUTk2wWfHdg+4G6kW8KdMcp3kChhKWzR3T76bV9yybDsuoYq/6aWFQtIgEJLMFcTUpwk0PodA==} + hasBin: true + dependencies: + '@babel/runtime': 7.23.2 + '@thewtex/zstddec': 0.2.0 + '@types/emscripten': 1.39.9 + axios: 1.6.0 + comlink: 4.4.1 + commander: 9.5.0 + fs-extra: 10.1.0 + glob: 8.1.0 + markdown-table: 3.0.3 + mime-types: 2.1.35 + wasm-feature-detect: 1.6.1 + transitivePeerDependencies: + - debug + dev: false + + /joi@17.11.0: + resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: true + + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + dev: true + + /json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: true + + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + /jsprim@2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: true + + /lazy-ass@1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + dev: true + + /listr2@3.14.0(enquirer@2.4.1): + resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} + engines: {node: '>=10.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.20 + enquirer: 2.4.1 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.3.0 + rxjs: 7.8.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + dev: true + + /lit-element@4.0.1: + resolution: {integrity: sha512-OxRMJem4HKZt0320HplLkBPoi4KHiEHoPHKd8Lzf07ZQVAOKIjZ32yPLRKRDEolFU1RgrQBfSHQMoxKZ72V3Kw==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.1.2 + '@lit/reactive-element': 2.0.1 + lit-html: 3.0.2 + dev: true + + /lit-html@3.0.2: + resolution: {integrity: sha512-Q1A5lHza3bnmxoWJn6yS6vQZQdExl4fghk8W1G+jnAEdoFNYo5oeBBb/Ol7zSEdKd3TR7+r0zsJQyuWEVguiyQ==} + dependencies: + '@types/trusted-types': 2.0.5 + dev: true + + /lit@3.0.2: + resolution: {integrity: sha512-ZoVUPGgXOQocP4OvxehEOBmC4rWB4cRYDPaz7aFmH8DFytsCi/NeACbr4C6vNPGDEC07BrhUos7uVNayDKLQ2Q==} + dependencies: + '@lit/reactive-element': 2.0.1 + lit-element: 4.0.1 + lit-html: 3.0.2 + dev: true + + /load-json-file@7.0.1: + resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + dependencies: + p-defer: 1.0.0 + dev: true + + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: true + + /markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + dev: false + + /matcher@5.0.0: + resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + dependencies: + blueimp-md5: 2.19.0 + dev: true + + /mem@9.0.2: + resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} + engines: {node: '>=12.20'} + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 4.0.0 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: false + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /nanoid@3.3.6: + resolution: {integrity: sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /ospath@1.2.2: + resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + dev: true + + /p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + dev: true + + /p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-timeout: 5.1.0 + dev: true + + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + dependencies: + aggregate-error: 4.0.1 + dev: true + + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + dev: true + + /parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + dev: true + + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: true + + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: true + + /performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pkg-conf@4.0.0: + resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + find-up: 6.3.0 + load-json-file: 7.0.1 + dev: true + + /plur@5.1.0: + resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + irregular-plurals: 3.5.0 + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.6 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + dev: true + + /pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + dependencies: + parse-ms: 3.0.0 + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /proxy-from-env@1.0.0: + resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + dev: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + + /ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: true + + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /qr-creator@1.0.0: + resolution: {integrity: sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==} + dev: true + + /qs@6.10.4: + resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.22.8 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + + /request-progress@3.0.0: + resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} + dependencies: + throttleit: 1.0.0 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.6.2 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + dependencies: + type-fest: 0.13.1 + dev: true + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /shell-quote@1.8.1: + resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} + dev: true + + /shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + dev: true + + /shx@0.3.4: + resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.8 + shelljs: 0.8.5 + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + dev: true + + /slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /spawn-command@0.0.2: + resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + dev: true + + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /start-server-and-test@2.0.1: + resolution: {integrity: sha512-8PFo4DLLLCDMuS51/BEEtE1m9CAXw1LNVtZSS1PzkYQh6Qf9JUwM4huYeSoUumaaoAyuwYBwCa9OsrcpMqcOdQ==} + engines: {node: '>=16'} + hasBin: true + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.3.4(supports-color@8.1.1) + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 7.0.1(debug@4.3.4) + transitivePeerDependencies: + - supports-color + dev: true + + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /supertap@3.0.1: + resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + indent-string: 5.0.0 + js-yaml: 3.14.1 + serialize-error: 7.0.1 + strip-ansi: 7.1.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + + /throttleit@1.0.0: + resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + dev: true + + /tmp@0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + + /tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + dev: true + + /type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: true + + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + + /verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + dev: true + + /vite-plugin-static-copy@0.17.0(vite@4.5.0): + resolution: {integrity: sha512-2HpNbHfDt8SDy393AGXh9llHkc8FJMQkI8s3T5WsH3SWLMO+f5cFIyPErl4yGKU9Uh3Vaqsd4lHZYTf042fQ2A==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 + dependencies: + chokidar: 3.5.3 + fast-glob: 3.3.1 + fs-extra: 11.1.1 + picocolors: 1.0.0 + vite: 4.5.0(@types/node@20.8.10) + dev: true + + /vite@4.5.0(@types/node@20.8.10): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.8.10 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /wait-on@7.0.1(debug@4.3.4): + resolution: {integrity: sha512-9AnJE9qTjRQOlTZIldAaf/da2eW0eSRSgcqq85mXQja/DW3MriHxkpODDSUEg+Gri/rKEcXUZHe+cevvYItaog==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + axios: 0.27.2(debug@4.3.4) + joi: 17.11.0 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.1 + transitivePeerDependencies: + - debug + dev: true + + /wasm-feature-detect@1.6.1: + resolution: {integrity: sha512-R1i9ED8UlLu/foILNB1ck9XS63vdtqU/tP1MCugVekETp/ySCrBZRk5I/zI67cI1wlQYeSonNm1PLjDHZDNg6g==} + dev: false + + /well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: true + + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true diff --git a/packages/image-io/typescript/src/index-worker-embedded.min.ts b/packages/image-io/typescript/src/index-worker-embedded.min.ts new file mode 100644 index 000000000..3144a3f5c --- /dev/null +++ b/packages/image-io/typescript/src/index-worker-embedded.min.ts @@ -0,0 +1,5 @@ +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.min.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' diff --git a/packages/image-io/typescript/src/index-worker-embedded.ts b/packages/image-io/typescript/src/index-worker-embedded.ts index c9d87a447..c31c6236f 100644 --- a/packages/image-io/typescript/src/index-worker-embedded.ts +++ b/packages/image-io/typescript/src/index-worker-embedded.ts @@ -2,4 +2,4 @@ import { setPipelineWorkerUrl } from './index.js' import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js' setPipelineWorkerUrl(pipelineWorker) -export * from './index.js' \ No newline at end of file +export * from './index.js' diff --git a/src/bindgen/python/emscripten/emscripten-pyodide-module.js b/src/bindgen/python/emscripten/emscripten-pyodide-module.js index 59e0a9629..20f9f5182 100644 --- a/src/bindgen/python/emscripten/emscripten-pyodide-module.js +++ b/src/bindgen/python/emscripten/emscripten-pyodide-module.js @@ -4,19 +4,18 @@ import path from 'path' import writeIfOverrideNotPresent from '../../write-if-override-not-present.js' function emscriptenPyodideModule(outputDir, packageDir, pypackage, options) { - const defaultJsModuleName = options.packageName.replace('itkwasm-', '') - const defaultJsModulePath = path.join(outputDir, '..', 'typescript', 'dist', `${defaultJsModuleName}-worker-embedded.js`) + const defaultJsModulePath = path.join(outputDir, '..', 'typescript', 'dist', 'bundle', 'index-worker-embedded.min.js') const moduleUrl = options.jsModulePath ?? defaultJsModulePath if (!fs.existsSync(moduleUrl)) { console.error(`Could not find ${moduleUrl}`) process.exit(1) } - const jsModuleContent = fs.readFileSync(moduleUrl, { encoding: 'utf8', flag: 'r' }) + const jsModuleContent = btoa(fs.readFileSync(moduleUrl, { encoding: 'utf8', flag: 'r' })) const moduleContent = `from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ -default_js_module = """data:text/javascript;charset=utf-8,${jsModuleContent}""" +default_js_module = """data:text/javascript;base64,${jsModuleContent}""" default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) ` diff --git a/src/bindgen/python/resources/template.pyproject.toml b/src/bindgen/python/resources/template.pyproject.toml index ea53d1d95..ee55b8b50 100644 --- a/src/bindgen/python/resources/template.pyproject.toml +++ b/src/bindgen/python/resources/template.pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] keywords = [ "itkwasm", @@ -31,7 +32,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131",@bindgenDependencies@ + "itkwasm >= 1.0.b145",@bindgenDependencies@ ] [tool.hatch.version] diff --git a/src/bindgen/typescript/resources/index-worker-embedded.min.ts b/src/bindgen/typescript/resources/index-worker-embedded.min.ts new file mode 100644 index 000000000..315cc25b8 --- /dev/null +++ b/src/bindgen/typescript/resources/index-worker-embedded.min.ts @@ -0,0 +1,7 @@ +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.min.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' diff --git a/src/bindgen/typescript/resources/index-worker-embedded.ts b/src/bindgen/typescript/resources/index-worker-embedded.ts new file mode 100644 index 000000000..2b0680e5c --- /dev/null +++ b/src/bindgen/typescript/resources/index-worker-embedded.ts @@ -0,0 +1,7 @@ +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' \ No newline at end of file diff --git a/src/bindgen/typescript/resources/template.package.json b/src/bindgen/typescript/resources/template.package.json index 0e8926fbc..d55d02c85 100644 --- a/src/bindgen/typescript/resources/template.package.json +++ b/src/bindgen/typescript/resources/template.package.json @@ -3,23 +3,22 @@ "version": "0.1.0", "description": "", "type": "module", - "module": "./dist/bundles/bundle-name.js", + "module": "./dist/index.js", "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", - "browser": "./dist/bundle-name.js", - "node": "./dist/bundle-name-node.js", - "default": "./dist/bundles/bundle-name.js" + "browser": "./dist/index.js", + "node": "./dist/index-node.js", + "default": "./dist/index.js" } }, "scripts": { "start": "npm run copyShoelaceAssets && vite -c build/vite.config.js", "test": "echo \"Error: no test specified\" && exit 1", - "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", - "build:node": "esbuild --bundle --format=esm --banner:js=\"import { createRequire } from 'module';const require = createRequire(import.meta.url);\" --platform=node --outfile=./dist/index-node.js ./src/index-node.ts", - "build:browser": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/ && esbuild --bundle --format=esm --outfile=./dist/index.js ./src/index.ts", - "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build": "npm run build:tsc && npm run build:browser:workerEmbedded && npm run build:browser:workerEmbeddedMin && npm run build:demo", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build:browser:workerEmbeddedMin": "esbuild --minify --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.min.js ./src/index-worker-embedded.min.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" @@ -33,7 +32,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.152" + "itk-wasm": "^1.0.0-b.154" }, "devDependencies": { "@itk-wasm/image-io": "^0.2.0", @@ -42,7 +41,7 @@ "esbuild": "^0.19.5", "shx": "^0.3.4", "typescript": "^5.0.4", - "vite": "^4.4.11", + "vite": "^4.5.0", "vite-plugin-static-copy": "^0.17.0" } } diff --git a/src/bindgen/typescript/resources/vite.config.js b/src/bindgen/typescript/resources/vite.config.js index 38df171ce..5266d1417 100644 --- a/src/bindgen/typescript/resources/vite.config.js +++ b/src/bindgen/typescript/resources/vite.config.js @@ -12,14 +12,14 @@ export default defineConfig({ format: 'es' }, optimizeDeps: { - exclude: ['@itk-wasm/image-io'] + exclude: ['itk-wasm', '@itk-wasm/image-io'] }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, - { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm.zst}', dest: 'pipelines' }, + { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm,wasm.zst}', dest: 'pipelines' }, ], }) ], diff --git a/src/bindgen/typescript/typescript-bindings.js b/src/bindgen/typescript/typescript-bindings.js index 4bc1bf564..c268469d1 100644 --- a/src/bindgen/typescript/typescript-bindings.js +++ b/src/bindgen/typescript/typescript-bindings.js @@ -73,6 +73,7 @@ function typescriptBindings (outputDir, buildDir, wasmBinaries, options, forNode if (!forNode) { indexContent += "export * from './pipelines-base-url.js'\n" + indexContent += "export * from './pipeline-worker-url.js'\n" } writeSupportFiles(outputDir, forNode, bindgenResource, packageName, options.packageDescription) diff --git a/src/bindgen/typescript/write-support-files.js b/src/bindgen/typescript/write-support-files.js index 6a72de106..ab6392918 100644 --- a/src/bindgen/typescript/write-support-files.js +++ b/src/bindgen/typescript/write-support-files.js @@ -30,6 +30,18 @@ function writeSupportFiles(outputDir, forNode, bindgenResource, packageName, pac fs.writeFileSync(pipelineWorkerUrlPath, pipelineWorkerUrlPathContent) } + const indexWorkerEmbeddedPath = path.join(outputDir, 'src', 'index-worker-embedded.ts') + const indexWorkerEmbeddedContent = fs.readFileSync(bindgenResource('index-worker-embedded.ts'), { encoding: 'utf8', flag: 'r' }) + writeIfOverrideNotPresent(indexWorkerEmbeddedPath, indexWorkerEmbeddedContent) + const indexWorkerEmbeddedMinPath = path.join(outputDir, 'src', 'index-worker-embedded.min.ts') + const indexWorkerEmbeddedMinContent = fs.readFileSync(bindgenResource('index-worker-embedded.min.ts'), { encoding: 'utf8', flag: 'r' }) + writeIfOverrideNotPresent(indexWorkerEmbeddedMinPath, indexWorkerEmbeddedMinContent) + + const packageJsonSymlinkPath = path.join(outputDir, 'src', 'package.json') + if (!fs.existsSync(packageJsonSymlinkPath)) { + fs.symlinkSync('../package.json', packageJsonSymlinkPath) + } + const npmIgnorePath = path.join(outputDir, '.npmignore') if (!fs.existsSync(npmIgnorePath)) { fs.copyFileSync(bindgenResource('npmignore.bindgen'), npmIgnorePath) From 2302ec44fca6c8b594576d180ae4d737bdb69605 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 8 Nov 2023 06:58:00 -0500 Subject: [PATCH 18/23] test(image-io): add python emscirpten tests --- .../itkwasm_image_io/__init__.py | 2 + .../itkwasm_image_io/read_image_async.py | 49 ++++++++++++++ .../itkwasm_image_io/write_image.py | 2 +- .../itkwasm_image_io/write_image_async.py | 43 ++++++++++++ .../python/itkwasm-image-io/pyproject.toml | 20 +++++- .../python/itkwasm-image-io/tests/fixtures.py | 29 +++++++++ .../tests/test_bio_rad_async.py | 57 ++++++++++++++++ .../tests/test_metaimage_async.py | 65 +++++++++++++++++++ .../tests/test_read_write_image_async.py | 62 ++++++++++++++++++ 9 files changed, 325 insertions(+), 4 deletions(-) create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/fixtures.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/test_bio_rad_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/test_metaimage_async.py create mode 100644 packages/image-io/python/itkwasm-image-io/tests/test_read_write_image_async.py diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py index 3f2b7bc42..a37361b45 100644 --- a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/__init__.py @@ -2,6 +2,8 @@ from .read_image import read_image, imread from .write_image import write_image, imwrite +from .read_image_async import read_image_async, imread_async +from .write_image_async import write_image_async, imwrite_async from .bio_rad_read_image_async import bio_rad_read_image_async from .bio_rad_read_image import bio_rad_read_image diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image_async.py new file mode 100644 index 000000000..6c88f8684 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/read_image_async.py @@ -0,0 +1,49 @@ +import os +from typing import Optional, Union + +from itkwasm import ( + environment_dispatch, + Image, + PixelTypes, + IntTypes, + FloatTypes, +) + +async def read_image_async( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + """Read an image file format and convert it to the itk-wasm file format + + :param serialized_image: Input image serialized in the file format + :type serialized_image: os.PathLike + + :param information_only: Only read image metadata -- do not read pixel data. + :type information_only: bool + + :param pixel_type: Pixel type to cast to. + :type pixel_Type: Optional[PixelTypes] + + :param component_type: Component type to cast to. + :type component_type: Optional[Union[IntTypes, FloatTypes]] + + :return: Output image + :rtype: Image + """ + func = environment_dispatch("itkwasm_image_io", "read_image_async") + output = await func(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type) + return output + +async def imread_async( + serialized_image: os.PathLike, + information_only: bool = False, + pixel_type: Optional[PixelTypes]=None, + component_type: Optional[Union[IntTypes, FloatTypes]]=None, +) -> Image: + return await read_image_async(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type) + +imread_async.__doc__ = f"""{read_image_async.__doc__} + Alias for read_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py index 692ec5428..2526436da 100644 --- a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image.py @@ -26,7 +26,7 @@ def write_image( :param use_compression: Use compression in the written file :type use_compression: bool """ - func = environment_dispatch("itkwasm_image_io", "png_write_image") + func = environment_dispatch("itkwasm_image_io", "write_image") func(image, serialized_image, information_only=information_only, use_compression=use_compression) return diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image_async.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image_async.py new file mode 100644 index 000000000..83ba37432 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/write_image_async.py @@ -0,0 +1,43 @@ +import os +from typing import Dict, Tuple, Optional, List, Any + +from itkwasm import ( + environment_dispatch, + Image, +) + +async def write_image_async( + image: Image, + serialized_image: str, + information_only: bool = False, + use_compression: bool = False, +) -> None: + """Write an itk-wasm file format converted to an image file format + + :param image: Input image + :type image: Image + + :param serialized_image: Output image serialized in the file format. + :type serialized_image: str + + :param information_only: Only write image metadata -- do not write pixel data. + :type information_only: bool + + :param use_compression: Use compression in the written file + :type use_compression: bool + """ + func = environment_dispatch("itkwasm_image_io", "write_image_async") + await func(image, serialized_image, information_only=information_only, use_compression=use_compression) + return + +async def imwrite_async( + image: Image, + serialized_image: os.PathLike, + information_only: bool = False, + use_compression: bool = False, +) -> None: + return await write_image_async(image, serialized_image, information_only=information_only, use_compression=use_compression) + +imwrite_async.__doc__ = f"""{write_image_async.__doc__} + Alias for write_image. + """ \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/pyproject.toml b/packages/image-io/python/itkwasm-image-io/pyproject.toml index eb0eee3ec..5a5ee739d 100644 --- a/packages/image-io/python/itkwasm-image-io/pyproject.toml +++ b/packages/image-io/python/itkwasm-image-io/pyproject.toml @@ -33,7 +33,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", "itkwasm-image-io-wasi; sys_platform != \"emscripten\"", "itkwasm-image-io-emscripten; sys_platform == \"emscripten\"", @@ -45,6 +45,7 @@ path = "itkwasm_image_io/_version.py" [tool.hatch.envs.default] dependencies = [ "pytest", + "pytest-pyodide", ] [project.urls] @@ -52,8 +53,21 @@ Home = "https://github.com/InsightSoftwareConsortium/itk-wasm" Source = "https://github.com/InsightSoftwareConsortium/itk-wasm" [tool.hatch.envs.default.scripts] -test = "pytest" - +test = [ + "hatch build -t wheel", + "pytest --dist-dir=./dist --rt=chrome", +] +download-pyodide = [ + "curl -L https://github.com/pyodide/pyodide/releases/download/0.24.1/pyodide-0.24.1.tar.bz2 -o pyodide.tar.bz2", + "tar xjf pyodide.tar.bz2", + "rm -rf dist pyodide.tar.bz2", + "mv pyodide dist", +] +serve = [ + "hatch build -t wheel", + 'echo "\nVisit http://localhost:8877/console.html\n"', + "python -m http.server --directory=./dist 8877", +] [tool.hatch.build] exclude = [ diff --git a/packages/image-io/python/itkwasm-image-io/tests/fixtures.py b/packages/image-io/python/itkwasm-image-io/tests/fixtures.py new file mode 100644 index 000000000..324b9aa7a --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/fixtures.py @@ -0,0 +1,29 @@ +import pytest +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide + +from itkwasm_image_io import __version__ as test_package_version + +@pytest.fixture +def package_wheel(): + return f"itkwasm_image_io-{test_package_version}-py3-none-any.whl" + +@pytest.fixture +def input_data(): + from pathlib import Path + input_base_path = Path('..', '..', 'test', 'data') + test_files = [ + Path('input') / 'cthead1.png', + Path('input') / 'biorad.pic', + Path('input') / 'brainweb165a10f17.mha', + ] + data = {} + for f in test_files: + with open(input_base_path / f, 'rb') as fp: + print(str(f.name)) + data[str(f.name)] = fp.read() + return data \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/tests/test_bio_rad_async.py b/packages/image-io/python/itkwasm-image-io/tests/test_bio_rad_async.py new file mode 100644 index 000000000..16e8c6266 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/test_bio_rad_async.py @@ -0,0 +1,57 @@ +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide +from .fixtures import package_wheel, input_data + +@run_in_pyodide(packages=['micropip']) +async def test_bio_rad_async(selenium, package_wheel, input_data): + import micropip + await micropip.install(package_wheel) + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) + + from pathlib import Path + + from itkwasm_image_io import bio_rad_read_image_async, bio_rad_write_image_async + + def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 0.06000000238418579 + assert image.spacing[1] == 0.06000000238418579 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 768 + assert image.size[1] == 512 + assert image.data.shape[1] == 768 + assert image.data.shape[0] == 512 + assert image.data.ravel()[1000] == 27 + + test_file_path = 'biorad.pic' + write_input_data_to_fs(input_data, test_file_path) + + assert Path(test_file_path).exists() + + could_read, image = await bio_rad_read_image_async(test_file_path) + assert could_read + verify_image(image) + + test_output_file_path = 'biorad_out.pic' + + use_compression = False + could_write = await bio_rad_write_image_async(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = await bio_rad_read_image_async(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/tests/test_metaimage_async.py b/packages/image-io/python/itkwasm-image-io/tests/test_metaimage_async.py new file mode 100644 index 000000000..e75454e52 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/test_metaimage_async.py @@ -0,0 +1,65 @@ +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide +from .fixtures import package_wheel, input_data + +@run_in_pyodide(packages=['micropip']) +async def test_metaimage_async(selenium, package_wheel, input_data): + import micropip + await micropip.install(package_wheel) + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) + + from pathlib import Path + + from itkwasm_image_io_emscripten import meta_read_image_async, meta_write_image_async + + test_input_file_path = 'brainweb165a10f17.mha' + test_output_file_path = 'meta-image-test-brainweb165a10f17.mha' + + def verify_image(image): + assert image.imageType.dimension == 3 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "Scalar" + assert image.imageType.components == 1 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.origin[2] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.spacing[2] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[0, 2] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.direction[1, 2] == 0.0 + assert image.direction[2, 0] == 0.0 + assert image.direction[2, 1] == 0.0 + assert image.direction[2, 2] == 1.0 + assert image.size[0] == 181 + assert image.size[1] == 217 + assert image.size[2] == 180 + assert image.data.ravel()[0] == 5 + assert image.data.ravel()[1] == 8 + assert image.data.ravel()[2] == 2 + + write_input_data_to_fs(input_data, test_input_file_path) + + assert Path(test_input_file_path).exists() + + could_read, image = await meta_read_image_async(test_input_file_path) + assert could_read + verify_image(image) + + use_compression = False + could_write = await meta_write_image_async(image, test_output_file_path, use_compression) + assert could_write + + could_read, image = await meta_read_image_async(test_output_file_path) + assert could_read + verify_image(image) \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io/tests/test_read_write_image_async.py b/packages/image-io/python/itkwasm-image-io/tests/test_read_write_image_async.py new file mode 100644 index 000000000..1345224e8 --- /dev/null +++ b/packages/image-io/python/itkwasm-image-io/tests/test_read_write_image_async.py @@ -0,0 +1,62 @@ +import sys + +if sys.version_info < (3,10): + pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True) + +from pytest_pyodide import run_in_pyodide +from .fixtures import package_wheel, input_data + +@run_in_pyodide(packages=['micropip']) +async def test_read_write_image_async(selenium, package_wheel, input_data): + import micropip + await micropip.install(package_wheel) + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) + + from pathlib import Path + + from itkwasm_image_io import read_image_async, write_image_async, imread_async, imwrite_async + + test_input_file_path = "cthead1.png" + test_output_file_path = "read-write-cthead1.png" + + def verify_image(image): + assert image.imageType.dimension == 2 + assert image.imageType.componentType == "uint8" + assert image.imageType.pixelType == "RGB" + assert image.imageType.components == 3 + assert image.origin[0] == 0.0 + assert image.origin[1] == 0.0 + assert image.spacing[0] == 1.0 + assert image.spacing[1] == 1.0 + assert image.direction[0, 0] == 1.0 + assert image.direction[0, 1] == 0.0 + assert image.direction[1, 0] == 0.0 + assert image.direction[1, 1] == 1.0 + assert image.size[0] == 256 + assert image.size[1] == 256 + assert image.data.shape[1] == 256 + assert image.data.shape[0] == 256 + + write_input_data_to_fs(input_data, test_input_file_path) + + assert Path(test_input_file_path).exists() + + image = await read_image_async(test_input_file_path) + verify_image(image) + + use_compression = False + await write_image_async(image, test_output_file_path, use_compression=use_compression) + + image = await read_image_async(test_output_file_path) + verify_image(image) + + image = await imread_async(test_input_file_path) + verify_image(image) + + use_compression = False + await imwrite_async(image, test_output_file_path, use_compression=use_compression) + + image = await imread_async(test_output_file_path) + verify_image(image) \ No newline at end of file From c222c18651bc7a8f06c56464d33e704c5281965c Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 8 Nov 2023 07:52:30 -0500 Subject: [PATCH 19/23] build(compress-stringify): bump typescript for itk-wasm 1.0.0-b.154 --- .../_version.py | 2 +- .../js_package.py | 6 ++++-- .../pyproject.toml | 3 ++- .../_version.py | 2 +- .../itkwasm_compress_stringify/_version.py | 2 +- .../itkwasm-compress-stringify/pyproject.toml | 3 ++- .../compress-stringify/typescript/package.json | 10 +++++----- .../typescript/pnpm-lock.yaml | 18 +++++++++--------- .../src/index-worker-embedded.min.ts | 9 +++++++++ 9 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 packages/compress-stringify/typescript/src/index-worker-embedded.min.ts diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py index 5becc17c0..159d48b87 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/_version.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "2.0.1" diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/js_package.py b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/js_package.py index 3ff996913..09379d154 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/js_package.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/itkwasm_compress_stringify_emscripten/js_package.py @@ -1,6 +1,8 @@ +# Generated file. To retain edits, remove this comment. + from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ - -default_config = JsPackageConfig(f"https://cdn.jsdelivr.net/npm/@itk-wasm/compress-stringify@{__version__}/dist/bundles/compress-stringify.js") +default_js_module = """data:text/javascript;base64,dmFyIGF0PSIxLjAuMC1iLjE1NCIsej1hdDt2YXIgc3Q9e3BpcGVsaW5lV29ya2VyVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay13YXNtQCR7en0vZGlzdC9jb3JlL3dlYi13b3JrZXJzL2J1bmRsZXMvcGlwZWxpbmUubWluLndvcmtlci5qc2AsaW1hZ2VJT1VybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstaW1hZ2UtaW9AJHt6fWAsbWVzaElPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1tZXNoLWlvQCR7en1gLHBpcGVsaW5lc1VybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstd2FzbUAke3p9L2Rpc3QvcGlwZWxpbmVzYH0sSD1zdDt2YXIgSXQ9e1RleHRGaWxlOiJJbnRlcmZhY2VUZXh0RmlsZSIsQmluYXJ5RmlsZToiSW50ZXJmYWNlQmluYXJ5RmlsZSIsVGV4dFN0cmVhbToiSW50ZXJmYWNlVGV4dFN0cmVhbSIsQmluYXJ5U3RyZWFtOiJJbnRlcmZhY2VCaW5hcnlTdHJlYW0iLEltYWdlOiJJbnRlcmZhY2VJbWFnZSIsTWVzaDoiSW50ZXJmYWNlTWVzaCIsUG9seURhdGE6IkludGVyZmFjZVBvbHlEYXRhIixKc29uQ29tcGF0aWJsZToiSW50ZXJmYWNlSnNvbkNvbXBhdGlibGUifSxkPUl0O3ZhciBndD17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEY9Z3Q7dmFyIEN0PXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxQPUN0O3ZhciBCdD17VGV4dDoiVGV4dCIsQmluYXJ5OiJCaW5hcnkiLEltYWdlOiJJbWFnZSIsTWVzaDoiTWVzaCJ9LFI9QnQ7ZnVuY3Rpb24gbHQoQSxlKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIEYuVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDg6e3Q9bmV3IEludDhBcnJheShlKTticmVha31jYXNlIEYuVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShlKTticmVha31jYXNlIEYuSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIFAuRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KGUpO2JyZWFrfWNhc2UgUC5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoZSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIHc9bHQ7dmFyIGN0PXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBFdChBKXtpZihBPT1udWxsKXJldHVybltdO2xldCBlPVtdO2ZvcihsZXQgdD0wO3Q8QS5sZW5ndGg7dCsrKXtsZXQgcj1mdChBW3RdKTtyIT09bnVsbCYmZS5wdXNoKHIpfXJldHVybiBlfWZ1bmN0aW9uIGZ0KEEpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IGU9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/ZT1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJihlPUEpLGN0JiZlIGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDplfXZhciByZT1FdDtmdW5jdGlvbiBWKEEsZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIEEuYXBwbHkoZSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6UXR9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOlJBfT1PYmplY3QsYUE9KEE9PmU9PntsZXQgdD1RdC5jYWxsKGUpO3JldHVybiBBW3RdfHwoQVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSksTj1BPT4oQT1BLnRvTG93ZXJDYXNlKCksZT0+YUEoZSk9PT1BKSxzQT1BPT5lPT50eXBlb2YgZT09PUEse2lzQXJyYXk6WX09QXJyYXksWj1zQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24gdXQoQSl7cmV0dXJuIEEhPT1udWxsJiYhWihBKSYmQS5jb25zdHJ1Y3RvciE9PW51bGwmJiFaKEEuY29uc3RydWN0b3IpJiZVKEEuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZBLmNvbnN0cnVjdG9yLmlzQnVmZmVyKEEpfXZhciBvZT1OKCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIGR0KEEpe2xldCBlO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/ZT1BcnJheUJ1ZmZlci5pc1ZpZXcoQSk6ZT1BJiZBLmJ1ZmZlciYmb2UoQS5idWZmZXIpLGV9dmFyIHB0PXNBKCJzdHJpbmciKSxVPXNBKCJmdW5jdGlvbiIpLGFlPXNBKCJudW1iZXIiKSxJQT1BPT5BIT09bnVsbCYmdHlwZW9mIEE9PSJvYmplY3QiLG10PUE9PkE9PT0hMHx8QT09PSExLG9BPUE9PntpZihhQShBKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBlPVJBKEEpO3JldHVybihlPT09bnVsbHx8ZT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihlKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBBKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gQSl9LGh0PU4oIkRhdGUiKSx5dD1OKCJGaWxlIiksd3Q9TigiQmxvYiIpLER0PU4oIkZpbGVMaXN0IiksU3Q9QT0+SUEoQSkmJlUoQS5waXBlKSxidD1BPT57bGV0IGU7cmV0dXJuIEEmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJkEgaW5zdGFuY2VvZiBGb3JtRGF0YXx8VShBLmFwcGVuZCkmJigoZT1hQShBKSk9PT0iZm9ybWRhdGEifHxlPT09Im9iamVjdCImJlUoQS50b1N0cmluZykmJkEudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sRnQ9TigiVVJMU2VhcmNoUGFyYW1zIiksUnQ9QT0+QS50cmltP0EudHJpbSgpOkEucmVwbGFjZSgvXltcc1x1RkVGRlx4QTBdK3xbXHNcdUZFRkZceEEwXSskL2csIiIpO2Z1bmN0aW9uIFgoQSxlLHthbGxPd25LZXlzOnQ9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgcixuO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxZKEEpKWZvcihyPTAsbj1BLmxlbmd0aDtyPG47cisrKWUuY2FsbChudWxsLEFbcl0scixBKTtlbHNle2xldCBpPXQ/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSk6T2JqZWN0LmtleXMoQSksbz1pLmxlbmd0aCxDO2ZvcihyPTA7cjxvO3IrKylDPWlbcl0sZS5jYWxsKG51bGwsQVtDXSxDLEEpfX1mdW5jdGlvbiBzZShBLGUpe2U9ZS50b0xvd2VyQ2FzZSgpO2xldCB0PU9iamVjdC5rZXlzKEEpLHI9dC5sZW5ndGgsbjtmb3IoO3ItLSA+MDspaWYobj10W3JdLGU9PT1uLnRvTG93ZXJDYXNlKCkpcmV0dXJuIG47cmV0dXJuIG51bGx9dmFyIEllPSgoKT0+dHlwZW9mIGdsb2JhbFRoaXM8InUiP2dsb2JhbFRoaXM6dHlwZW9mIHNlbGY8InUiP3NlbGY6dHlwZW9mIHdpbmRvdzwidSI/d2luZG93Omdsb2JhbCkoKSxnZT1BPT4hWihBKSYmQSE9PUllO2Z1bmN0aW9uIEZBKCl7bGV0e2Nhc2VsZXNzOkF9PWdlKHRoaXMpJiZ0aGlzfHx7fSxlPXt9LHQ9KHIsbik9PntsZXQgaT1BJiZzZShlLG4pfHxuO29BKGVbaV0pJiZvQShyKT9lW2ldPUZBKGVbaV0scik6b0Eocik/ZVtpXT1GQSh7fSxyKTpZKHIpP2VbaV09ci5zbGljZSgpOmVbaV09cn07Zm9yKGxldCByPTAsbj1hcmd1bWVudHMubGVuZ3RoO3I8bjtyKyspYXJndW1lbnRzW3JdJiZYKGFyZ3VtZW50c1tyXSx0KTtyZXR1cm4gZX12YXIga3Q9KEEsZSx0LHthbGxPd25LZXlzOnJ9PXt9KT0+KFgoZSwobixpKT0+e3QmJlUobik/QVtpXT1WKG4sdCk6QVtpXT1ufSx7YWxsT3duS2V5czpyfSksQSksVXQ9QT0+KEEuY2hhckNvZGVBdCgwKT09PTY1Mjc5JiYoQT1BLnNsaWNlKDEpKSxBKSxOdD0oQSxlLHQscik9PntBLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUucHJvdG90eXBlLHIpLEEucHJvdG90eXBlLmNvbnN0cnVjdG9yPUEsT2JqZWN0LmRlZmluZVByb3BlcnR5KEEsInN1cGVyIix7dmFsdWU6ZS5wcm90b3R5cGV9KSx0JiZPYmplY3QuYXNzaWduKEEucHJvdG90eXBlLHQpfSxPdD0oQSxlLHQscik9PntsZXQgbixpLG8sQz17fTtpZihlPWV8fHt9LEE9PW51bGwpcmV0dXJuIGU7ZG97Zm9yKG49T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSksaT1uLmxlbmd0aDtpLS0gPjA7KW89bltpXSwoIXJ8fHIobyxBLGUpKSYmIUNbb10mJihlW29dPUFbb10sQ1tvXT0hMCk7QT10IT09ITEmJlJBKEEpfXdoaWxlKEEmJighdHx8dChBLGUpKSYmQSE9PU9iamVjdC5wcm90b3R5cGUpO3JldHVybiBlfSxHdD0oQSxlLHQpPT57QT1TdHJpbmcoQSksKHQ9PT12b2lkIDB8fHQ+QS5sZW5ndGgpJiYodD1BLmxlbmd0aCksdC09ZS5sZW5ndGg7bGV0IHI9QS5pbmRleE9mKGUsdCk7cmV0dXJuIHIhPT0tMSYmcj09PXR9LEx0PUE9PntpZighQSlyZXR1cm4gbnVsbDtpZihZKEEpKXJldHVybiBBO2xldCBlPUEubGVuZ3RoO2lmKCFhZShlKSlyZXR1cm4gbnVsbDtsZXQgdD1uZXcgQXJyYXkoZSk7Zm9yKDtlLS0gPjA7KXRbZV09QVtlXTtyZXR1cm4gdH0sVHQ9KEE9PmU9PkEmJmUgaW5zdGFuY2VvZiBBKSh0eXBlb2YgVWludDhBcnJheTwidSImJlJBKFVpbnQ4QXJyYXkpKSx4dD0oQSxlKT0+e2xldCByPShBJiZBW1N5bWJvbC5pdGVyYXRvcl0pLmNhbGwoQSksbjtmb3IoOyhuPXIubmV4dCgpKSYmIW4uZG9uZTspe2xldCBpPW4udmFsdWU7ZS5jYWxsKEEsaVswXSxpWzFdKX19LFB0PShBLGUpPT57bGV0IHQscj1bXTtmb3IoOyh0PUEuZXhlYyhlKSkhPT1udWxsOylyLnB1c2godCk7cmV0dXJuIHJ9LE10PU4oIkhUTUxGb3JtRWxlbWVudCIpLEp0PUE9PkEudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bLV9cc10oW2EtelxkXSkoXHcqKS9nLGZ1bmN0aW9uKHQscixuKXtyZXR1cm4gci50b1VwcGVyQ2FzZSgpK259KSxuZT0oKHtoYXNPd25Qcm9wZXJ0eTpBfSk9PihlLHQpPT5BLmNhbGwoZSx0KSkoT2JqZWN0LnByb3RvdHlwZSksSHQ9TigiUmVnRXhwIiksQ2U9KEEsZSk9PntsZXQgdD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyhBKSxyPXt9O1godCwobixpKT0+e2xldCBvOyhvPWUobixpLEEpKSE9PSExJiYocltpXT1vfHxuKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEEscil9LFl0PUE9PntDZShBLChlLHQpPT57aWYoVShBKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKHQpIT09LTEpcmV0dXJuITE7bGV0IHI9QVt0XTtpZihVKHIpKXtpZihlLmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIGUpe2Uud3JpdGFibGU9ITE7cmV0dXJufWUuc2V0fHwoZS5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgJyIrdCsiJyIpfSl9fSl9LHF0PShBLGUpPT57bGV0IHQ9e30scj1uPT57bi5mb3JFYWNoKGk9Pnt0W2ldPSEwfSl9O3JldHVybiBZKEEpP3IoQSk6cihTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LEt0PSgpPT57fSx2dD0oQSxlKT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6ZSksYkE9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6IixpZT0iMDEyMzQ1Njc4OSIsQmU9e0RJR0lUOmllLEFMUEhBOmJBLEFMUEhBX0RJR0lUOmJBK2JBLnRvVXBwZXJDYXNlKCkraWV9LGp0PShBPTE2LGU9QmUuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpyfT1lO2Zvcig7QS0tOyl0Kz1lW01hdGgucmFuZG9tKCkqcnwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gV3QoQSl7cmV0dXJuISEoQSYmVShBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIF90PUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KHIsbik9PntpZihJQShyKSl7aWYoZS5pbmRleE9mKHIpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gcikpe2Vbbl09cjtsZXQgaT1ZKHIpP1tdOnt9O3JldHVybiBYKHIsKG8sQyk9PntsZXQgRT10KG8sbisxKTshWihFKSYmKGlbQ109RSl9KSxlW25dPXZvaWQgMCxpfX1yZXR1cm4gcn07cmV0dXJuIHQoQSwwKX0senQ9TigiQXN5bmNGdW5jdGlvbiIpLFZ0PUE9PkEmJihJQShBKXx8VShBKSkmJlUoQS50aGVuKSYmVShBLmNhdGNoKSxzPXtpc0FycmF5OlksaXNBcnJheUJ1ZmZlcjpvZSxpc0J1ZmZlcjp1dCxpc0Zvcm1EYXRhOmJ0LGlzQXJyYXlCdWZmZXJWaWV3OmR0LGlzU3RyaW5nOnB0LGlzTnVtYmVyOmFlLGlzQm9vbGVhbjptdCxpc09iamVjdDpJQSxpc1BsYWluT2JqZWN0Om9BLGlzVW5kZWZpbmVkOlosaXNEYXRlOmh0LGlzRmlsZTp5dCxpc0Jsb2I6d3QsaXNSZWdFeHA6SHQsaXNGdW5jdGlvbjpVLGlzU3RyZWFtOlN0LGlzVVJMU2VhcmNoUGFyYW1zOkZ0LGlzVHlwZWRBcnJheTpUdCxpc0ZpbGVMaXN0OkR0LGZvckVhY2g6WCxtZXJnZTpGQSxleHRlbmQ6a3QsdHJpbTpSdCxzdHJpcEJPTTpVdCxpbmhlcml0czpOdCx0b0ZsYXRPYmplY3Q6T3Qsa2luZE9mOmFBLGtpbmRPZlRlc3Q6TixlbmRzV2l0aDpHdCx0b0FycmF5Okx0LGZvckVhY2hFbnRyeTp4dCxtYXRjaEFsbDpQdCxpc0hUTUxGb3JtOk10LGhhc093blByb3BlcnR5Om5lLGhhc093blByb3A6bmUscmVkdWNlRGVzY3JpcHRvcnM6Q2UsZnJlZXplTWV0aG9kczpZdCx0b09iamVjdFNldDpxdCx0b0NhbWVsQ2FzZTpKdCxub29wOkt0LHRvRmluaXRlTnVtYmVyOnZ0LGZpbmRLZXk6c2UsZ2xvYmFsOkllLGlzQ29udGV4dERlZmluZWQ6Z2UsQUxQSEFCRVQ6QmUsZ2VuZXJhdGVTdHJpbmc6anQsaXNTcGVjQ29tcGxpYW50Rm9ybTpXdCx0b0pTT05PYmplY3Q6X3QsaXNBc3luY0ZuOnp0LGlzVGhlbmFibGU6VnR9O2Z1bmN0aW9uIHEoQSxlLHQscixuKXtFcnJvci5jYWxsKHRoaXMpLEVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsdGhpcy5jb25zdHJ1Y3Rvcik6dGhpcy5zdGFjaz1uZXcgRXJyb3IoKS5zdGFjayx0aGlzLm1lc3NhZ2U9QSx0aGlzLm5hbWU9IkF4aW9zRXJyb3IiLGUmJih0aGlzLmNvZGU9ZSksdCYmKHRoaXMuY29uZmlnPXQpLHImJih0aGlzLnJlcXVlc3Q9ciksbiYmKHRoaXMucmVzcG9uc2U9bil9cy5pbmhlcml0cyhxLEVycm9yLHt0b0pTT046ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6cy50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX19KTt2YXIgbGU9cS5wcm90b3R5cGUsY2U9e307WyJFUlJfQkFEX09QVElPTl9WQUxVRSIsIkVSUl9CQURfT1BUSU9OIiwiRUNPTk5BQk9SVEVEIiwiRVRJTUVET1VUIiwiRVJSX05FVFdPUksiLCJFUlJfRlJfVE9PX01BTllfUkVESVJFQ1RTIiwiRVJSX0RFUFJFQ0FURUQiLCJFUlJfQkFEX1JFU1BPTlNFIiwiRVJSX0JBRF9SRVFVRVNUIiwiRVJSX0NBTkNFTEVEIiwiRVJSX05PVF9TVVBQT1JUIiwiRVJSX0lOVkFMSURfVVJMIl0uZm9yRWFjaChBPT57Y2VbQV09e3ZhbHVlOkF9fSk7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMocSxjZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KGxlLCJpc0F4aW9zRXJyb3IiLHt2YWx1ZTohMH0pO3EuZnJvbT0oQSxlLHQscixuLGkpPT57bGV0IG89T2JqZWN0LmNyZWF0ZShsZSk7cmV0dXJuIHMudG9GbGF0T2JqZWN0KEEsbyxmdW5jdGlvbihFKXtyZXR1cm4gRSE9PUVycm9yLnByb3RvdHlwZX0sQz0+QyE9PSJpc0F4aW9zRXJyb3IiKSxxLmNhbGwobyxBLm1lc3NhZ2UsZSx0LHIsbiksby5jYXVzZT1BLG8ubmFtZT1BLm5hbWUsaSYmT2JqZWN0LmFzc2lnbihvLGkpLG99O3ZhciBRPXE7dmFyIGdBPW51bGw7ZnVuY3Rpb24ga0EoQSl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChBKXx8cy5pc0FycmF5KEEpfWZ1bmN0aW9uIGZlKEEpe3JldHVybiBzLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIEVlKEEsZSx0KXtyZXR1cm4gQT9BLmNvbmNhdChlKS5tYXAoZnVuY3Rpb24obixpKXtyZXR1cm4gbj1mZShuKSwhdCYmaT8iWyIrbisiXSI6bn0pLmpvaW4odD8iLiI6IiIpOmV9ZnVuY3Rpb24gWnQoQSl7cmV0dXJuIHMuaXNBcnJheShBKSYmIUEuc29tZShrQSl9dmFyIFh0PXMudG9GbGF0T2JqZWN0KHMse30sbnVsbCxmdW5jdGlvbihlKXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QoZSl9KTtmdW5jdGlvbiAkdChBLGUsdCl7aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7ZT1lfHxuZXcoZ0F8fEZvcm1EYXRhKSx0PXMudG9GbGF0T2JqZWN0KHQse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLHApe3JldHVybiFzLmlzVW5kZWZpbmVkKHBbZl0pfSk7bGV0IHI9dC5tZXRhVG9rZW5zLG49dC52aXNpdG9yfHxhLGk9dC5kb3RzLG89dC5pbmRleGVzLEU9KHQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmcy5pc1NwZWNDb21wbGlhbnRGb3JtKGUpO2lmKCFzLmlzRnVuY3Rpb24obikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBJKGwpe2lmKGw9PT1udWxsKXJldHVybiIiO2lmKHMuaXNEYXRlKGwpKXJldHVybiBsLnRvSVNPU3RyaW5nKCk7aWYoIUUmJnMuaXNCbG9iKGwpKXRocm93IG5ldyBRKCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBzLmlzQXJyYXlCdWZmZXIobCl8fHMuaXNUeXBlZEFycmF5KGwpP0UmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtsXSk6QnVmZmVyLmZyb20obCk6bH1mdW5jdGlvbiBhKGwsZixwKXtsZXQgeT1sO2lmKGwmJiFwJiZ0eXBlb2YgbD09Im9iamVjdCIpe2lmKHMuZW5kc1dpdGgoZiwie30iKSlmPXI/ZjpmLnNsaWNlKDAsLTIpLGw9SlNPTi5zdHJpbmdpZnkobCk7ZWxzZSBpZihzLmlzQXJyYXkobCkmJlp0KGwpfHwocy5pc0ZpbGVMaXN0KGwpfHxzLmVuZHNXaXRoKGYsIltdIikpJiYoeT1zLnRvQXJyYXkobCkpKXJldHVybiBmPWZlKGYpLHkuZm9yRWFjaChmdW5jdGlvbihoLFNBKXshKHMuaXNVbmRlZmluZWQoaCl8fGg9PT1udWxsKSYmZS5hcHBlbmQobz09PSEwP0VlKFtmXSxTQSxpKTpvPT09bnVsbD9mOmYrIltdIixJKGgpKX0pLCExfXJldHVybiBrQShsKT8hMDooZS5hcHBlbmQoRWUocCxmLGkpLEkobCkpLCExKX1sZXQgYz1bXSxCPU9iamVjdC5hc3NpZ24oWHQse2RlZmF1bHRWaXNpdG9yOmEsY29udmVydFZhbHVlOkksaXNWaXNpdGFibGU6a0F9KTtmdW5jdGlvbiBnKGwsZil7aWYoIXMuaXNVbmRlZmluZWQobCkpe2lmKGMuaW5kZXhPZihsKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Yy5wdXNoKGwpLHMuZm9yRWFjaChsLGZ1bmN0aW9uKHksdSl7KCEocy5pc1VuZGVmaW5lZCh5KXx8eT09PW51bGwpJiZuLmNhbGwoZSx5LHMuaXNTdHJpbmcodSk/dS50cmltKCk6dSxmLEIpKT09PSEwJiZnKHksZj9mLmNvbmNhdCh1KTpbdV0pfSksYy5wb3AoKX19aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBnKEEpLGV9dmFyIEc9JHQ7ZnVuY3Rpb24gUWUoQSl7bGV0IGU9eyIhIjoiJTIxIiwiJyI6IiUyNyIsIigiOiIlMjgiLCIpIjoiJTI5IiwifiI6IiU3RSIsIiUyMCI6IisiLCIlMDAiOiJcMCJ9O3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvWyEnKCl+XXwlMjB8JTAwL2csZnVuY3Rpb24ocil7cmV0dXJuIGVbcl19KX1mdW5jdGlvbiB1ZShBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJkcoQSx0aGlzLGUpfXZhciBkZT11ZS5wcm90b3R5cGU7ZGUuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O2RlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24ocil7cmV0dXJuIGUuY2FsbCh0aGlzLHIsUWUpfTpRZTtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKG4pe3JldHVybiB0KG5bMF0pKyI9Iit0KG5bMV0pfSwiIikuam9pbigiJiIpfTt2YXIgQ0E9dWU7ZnVuY3Rpb24gQXIoQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lM0EvZ2ksIjoiKS5yZXBsYWNlKC8lMjQvZywiJCIpLnJlcGxhY2UoLyUyQy9naSwiLCIpLnJlcGxhY2UoLyUyMC9nLCIrIikucmVwbGFjZSgvJTVCL2dpLCJbIikucmVwbGFjZSgvJTVEL2dpLCJdIil9ZnVuY3Rpb24gJChBLGUsdCl7aWYoIWUpcmV0dXJuIEE7bGV0IHI9dCYmdC5lbmNvZGV8fEFyLG49dCYmdC5zZXJpYWxpemUsaTtpZihuP2k9bihlLHQpOmk9cy5pc1VSTFNlYXJjaFBhcmFtcyhlKT9lLnRvU3RyaW5nKCk6bmV3IENBKGUsdCkudG9TdHJpbmcociksaSl7bGV0IG89QS5pbmRleE9mKCIjIik7byE9PS0xJiYoQT1BLnNsaWNlKDAsbykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIFVBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LHIpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6cj9yLnN5bmNocm9ub3VzOiExLHJ1bldoZW46cj9yLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihyKXtyIT09bnVsbCYmZShyKX0pfX0sTkE9VUE7dmFyIEJBPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgcGU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOkNBO3ZhciBtZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIGhlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIGVyPSgoKT0+e2xldCBBO3JldHVybiB0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmKChBPW5hdmlnYXRvci5wcm9kdWN0KT09PSJSZWFjdE5hdGl2ZSJ8fEE9PT0iTmF0aXZlU2NyaXB0Inx8QT09PSJOUyIpPyExOnR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUifSkoKSx0cj0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKSxEPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOnBlLEZvcm1EYXRhOm1lLEJsb2I6aGV9LGlzU3RhbmRhcmRCcm93c2VyRW52OmVyLGlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52OnRyLHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTtmdW5jdGlvbiBPQShBLGUpe3JldHVybiBHKEEsbmV3IEQuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LHIsbixpKXtyZXR1cm4gRC5pc05vZGUmJnMuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKHIsdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LGUpKX1mdW5jdGlvbiBycihBKXtyZXR1cm4gcy5tYXRjaEFsbCgvXHcrfFxbKFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIG5yKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSkscixuPXQubGVuZ3RoLGk7Zm9yKHI9MDtyPG47cisrKWk9dFtyXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gaXIoQSl7ZnVuY3Rpb24gZSh0LHIsbixpKXtsZXQgbz10W2krK10sQz1OdW1iZXIuaXNGaW5pdGUoK28pLEU9aT49dC5sZW5ndGg7cmV0dXJuIG89IW8mJnMuaXNBcnJheShuKT9uLmxlbmd0aDpvLEU/KHMuaGFzT3duUHJvcChuLG8pP25bb109W25bb10scl06bltvXT1yLCFDKTooKCFuW29dfHwhcy5pc09iamVjdChuW29dKSkmJihuW29dPVtdKSxlKHQscixuW29dLGkpJiZzLmlzQXJyYXkobltvXSkmJihuW29dPW5yKG5bb10pKSwhQyl9aWYocy5pc0Zvcm1EYXRhKEEpJiZzLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIHMuZm9yRWFjaEVudHJ5KEEsKHIsbik9PntlKHJyKHIpLG4sdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIGxBPWlyO2Z1bmN0aW9uIG9yKEEsZSx0KXtpZihzLmlzU3RyaW5nKEEpKXRyeXtyZXR1cm4oZXx8SlNPTi5wYXJzZSkoQSkscy50cmltKEEpfWNhdGNoKHIpe2lmKHIubmFtZSE9PSJTeW50YXhFcnJvciIpdGhyb3cgcn1yZXR1cm4odHx8SlNPTi5zdHJpbmdpZnkpKEEpfXZhciBHQT17dHJhbnNpdGlvbmFsOkJBLGFkYXB0ZXI6WyJ4aHIiLCJodHRwIl0sdHJhbnNmb3JtUmVxdWVzdDpbZnVuY3Rpb24oZSx0KXtsZXQgcj10LmdldENvbnRlbnRUeXBlKCl8fCIiLG49ci5pbmRleE9mKCJhcHBsaWNhdGlvbi9qc29uIik+LTEsaT1zLmlzT2JqZWN0KGUpO2lmKGkmJnMuaXNIVE1MRm9ybShlKSYmKGU9bmV3IEZvcm1EYXRhKGUpKSxzLmlzRm9ybURhdGEoZSkpcmV0dXJuIG4mJm4/SlNPTi5zdHJpbmdpZnkobEEoZSkpOmU7aWYocy5pc0FycmF5QnVmZmVyKGUpfHxzLmlzQnVmZmVyKGUpfHxzLmlzU3RyZWFtKGUpfHxzLmlzRmlsZShlKXx8cy5pc0Jsb2IoZSkpcmV0dXJuIGU7aWYocy5pc0FycmF5QnVmZmVyVmlldyhlKSlyZXR1cm4gZS5idWZmZXI7aWYocy5pc1VSTFNlYXJjaFBhcmFtcyhlKSlyZXR1cm4gdC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkO2NoYXJzZXQ9dXRmLTgiLCExKSxlLnRvU3RyaW5nKCk7bGV0IEM7aWYoaSl7aWYoci5pbmRleE9mKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiKT4tMSlyZXR1cm4gT0EoZSx0aGlzLmZvcm1TZXJpYWxpemVyKS50b1N0cmluZygpO2lmKChDPXMuaXNGaWxlTGlzdChlKSl8fHIuaW5kZXhPZigibXVsdGlwYXJ0L2Zvcm0tZGF0YSIpPi0xKXtsZXQgRT10aGlzLmVudiYmdGhpcy5lbnYuRm9ybURhdGE7cmV0dXJuIEcoQz97ImZpbGVzW10iOmV9OmUsRSYmbmV3IEUsdGhpcy5mb3JtU2VyaWFsaXplcil9fXJldHVybiBpfHxuPyh0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi9qc29uIiwhMSksb3IoZSkpOmV9XSx0cmFuc2Zvcm1SZXNwb25zZTpbZnVuY3Rpb24oZSl7bGV0IHQ9dGhpcy50cmFuc2l0aW9uYWx8fEdBLnRyYW5zaXRpb25hbCxyPXQmJnQuZm9yY2VkSlNPTlBhcnNpbmcsbj10aGlzLnJlc3BvbnNlVHlwZT09PSJqc29uIjtpZihlJiZzLmlzU3RyaW5nKGUpJiYociYmIXRoaXMucmVzcG9uc2VUeXBlfHxuKSl7bGV0IG89ISh0JiZ0LnNpbGVudEpTT05QYXJzaW5nKSYmbjt0cnl7cmV0dXJuIEpTT04ucGFyc2UoZSl9Y2F0Y2goQyl7aWYobyl0aHJvdyBDLm5hbWU9PT0iU3ludGF4RXJyb3IiP1EuZnJvbShDLFEuRVJSX0JBRF9SRVNQT05TRSx0aGlzLG51bGwsdGhpcy5yZXNwb25zZSk6Q319cmV0dXJuIGV9XSx0aW1lb3V0OjAseHNyZkNvb2tpZU5hbWU6IlhTUkYtVE9LRU4iLHhzcmZIZWFkZXJOYW1lOiJYLVhTUkYtVE9LRU4iLG1heENvbnRlbnRMZW5ndGg6LTEsbWF4Qm9keUxlbmd0aDotMSxlbnY6e0Zvcm1EYXRhOkQuY2xhc3Nlcy5Gb3JtRGF0YSxCbG9iOkQuY2xhc3Nlcy5CbG9ifSx2YWxpZGF0ZVN0YXR1czpmdW5jdGlvbihlKXtyZXR1cm4gZT49MjAwJiZlPDMwMH0saGVhZGVyczp7Y29tbW9uOntBY2NlcHQ6ImFwcGxpY2F0aW9uL2pzb24sIHRleHQvcGxhaW4sICovKiIsIkNvbnRlbnQtVHlwZSI6dm9pZCAwfX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJwb3N0IiwicHV0IiwicGF0Y2giXSxBPT57R0EuaGVhZGVyc1tBXT17fX0pO3ZhciBLPUdBO3ZhciBhcj1zLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLHllPUE9PntsZXQgZT17fSx0LHIsbjtyZXR1cm4gQSYmQS5zcGxpdChgCmApLmZvckVhY2goZnVuY3Rpb24obyl7bj1vLmluZGV4T2YoIjoiKSx0PW8uc3Vic3RyaW5nKDAsbikudHJpbSgpLnRvTG93ZXJDYXNlKCkscj1vLnN1YnN0cmluZyhuKzEpLnRyaW0oKSwhKCF0fHxlW3RdJiZhclt0XSkmJih0PT09InNldC1jb29raWUiP2VbdF0/ZVt0XS5wdXNoKHIpOmVbdF09W3JdOmVbdF09ZVt0XT9lW3RdKyIsICIrcjpyKX0pLGV9O3ZhciB3ZT1TeW1ib2woImludGVybmFscyIpO2Z1bmN0aW9uIEFBKEEpe3JldHVybiBBJiZTdHJpbmcoQSkudHJpbSgpLnRvTG93ZXJDYXNlKCl9ZnVuY3Rpb24gY0EoQSl7cmV0dXJuIEE9PT0hMXx8QT09bnVsbD9BOnMuaXNBcnJheShBKT9BLm1hcChjQSk6U3RyaW5nKEEpfWZ1bmN0aW9uIHNyKEEpe2xldCBlPU9iamVjdC5jcmVhdGUobnVsbCksdD0vKFteXHMsOz1dKylccyooPzo9XHMqKFteLDtdKykpPy9nLHI7Zm9yKDtyPXQuZXhlYyhBKTspZVtyWzFdXT1yWzJdO3JldHVybiBlfXZhciBJcj1BPT4vXlstX2EtekEtWjAtOV5gfH4sISMkJSYnKisuXSskLy50ZXN0KEEudHJpbSgpKTtmdW5jdGlvbiBMQShBLGUsdCxyLG4pe2lmKHMuaXNGdW5jdGlvbihyKSlyZXR1cm4gci5jYWxsKHRoaXMsZSx0KTtpZihuJiYoZT10KSwhIXMuaXNTdHJpbmcoZSkpe2lmKHMuaXNTdHJpbmcocikpcmV0dXJuIGUuaW5kZXhPZihyKSE9PS0xO2lmKHMuaXNSZWdFeHAocikpcmV0dXJuIHIudGVzdChlKX19ZnVuY3Rpb24gZ3IoQSl7cmV0dXJuIEEudHJpbSgpLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvKFthLXpcZF0pKFx3KikvZywoZSx0LHIpPT50LnRvVXBwZXJDYXNlKCkrcil9ZnVuY3Rpb24gQ3IoQSxlKXtsZXQgdD1zLnRvQ2FtZWxDYXNlKCIgIitlKTtbImdldCIsInNldCIsImhhcyJdLmZvckVhY2gocj0+e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLHIrdCx7dmFsdWU6ZnVuY3Rpb24obixpLG8pe3JldHVybiB0aGlzW3JdLmNhbGwodGhpcyxlLG4saSxvKX0sY29uZmlndXJhYmxlOiEwfSl9KX12YXIgdj1jbGFzc3tjb25zdHJ1Y3RvcihlKXtlJiZ0aGlzLnNldChlKX1zZXQoZSx0LHIpe2xldCBuPXRoaXM7ZnVuY3Rpb24gaShDLEUsSSl7bGV0IGE9QUEoRSk7aWYoIWEpdGhyb3cgbmV3IEVycm9yKCJoZWFkZXIgbmFtZSBtdXN0IGJlIGEgbm9uLWVtcHR5IHN0cmluZyIpO2xldCBjPXMuZmluZEtleShuLGEpOyghY3x8bltjXT09PXZvaWQgMHx8ST09PSEwfHxJPT09dm9pZCAwJiZuW2NdIT09ITEpJiYobltjfHxFXT1jQShDKSl9bGV0IG89KEMsRSk9PnMuZm9yRWFjaChDLChJLGEpPT5pKEksYSxFKSk7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChlKXx8ZSBpbnN0YW5jZW9mIHRoaXMuY29uc3RydWN0b3I/byhlLHQpOnMuaXNTdHJpbmcoZSkmJihlPWUudHJpbSgpKSYmIUlyKGUpP28oeWUoZSksdCk6ZSE9bnVsbCYmaSh0LGUsciksdGhpc31nZXQoZSx0KXtpZihlPUFBKGUpLGUpe2xldCByPXMuZmluZEtleSh0aGlzLGUpO2lmKHIpe2xldCBuPXRoaXNbcl07aWYoIXQpcmV0dXJuIG47aWYodD09PSEwKXJldHVybiBzcihuKTtpZihzLmlzRnVuY3Rpb24odCkpcmV0dXJuIHQuY2FsbCh0aGlzLG4scik7aWYocy5pc1JlZ0V4cCh0KSlyZXR1cm4gdC5leGVjKG4pO3Rocm93IG5ldyBUeXBlRXJyb3IoInBhcnNlciBtdXN0IGJlIGJvb2xlYW58cmVnZXhwfGZ1bmN0aW9uIil9fX1oYXMoZSx0KXtpZihlPUFBKGUpLGUpe2xldCByPXMuZmluZEtleSh0aGlzLGUpO3JldHVybiEhKHImJnRoaXNbcl0hPT12b2lkIDAmJighdHx8TEEodGhpcyx0aGlzW3JdLHIsdCkpKX1yZXR1cm4hMX1kZWxldGUoZSx0KXtsZXQgcj10aGlzLG49ITE7ZnVuY3Rpb24gaShvKXtpZihvPUFBKG8pLG8pe2xldCBDPXMuZmluZEtleShyLG8pO0MmJighdHx8TEEocixyW0NdLEMsdCkpJiYoZGVsZXRlIHJbQ10sbj0hMCl9fXJldHVybiBzLmlzQXJyYXkoZSk/ZS5mb3JFYWNoKGkpOmkoZSksbn1jbGVhcihlKXtsZXQgdD1PYmplY3Qua2V5cyh0aGlzKSxyPXQubGVuZ3RoLG49ITE7Zm9yKDtyLS07KXtsZXQgaT10W3JdOyghZXx8TEEodGhpcyx0aGlzW2ldLGksZSwhMCkpJiYoZGVsZXRlIHRoaXNbaV0sbj0hMCl9cmV0dXJuIG59bm9ybWFsaXplKGUpe2xldCB0PXRoaXMscj17fTtyZXR1cm4gcy5mb3JFYWNoKHRoaXMsKG4saSk9PntsZXQgbz1zLmZpbmRLZXkocixpKTtpZihvKXt0W29dPWNBKG4pLGRlbGV0ZSB0W2ldO3JldHVybn1sZXQgQz1lP2dyKGkpOlN0cmluZyhpKS50cmltKCk7QyE9PWkmJmRlbGV0ZSB0W2ldLHRbQ109Y0EobikscltDXT0hMH0pLHRoaXN9Y29uY2F0KC4uLmUpe3JldHVybiB0aGlzLmNvbnN0cnVjdG9yLmNvbmNhdCh0aGlzLC4uLmUpfXRvSlNPTihlKXtsZXQgdD1PYmplY3QuY3JlYXRlKG51bGwpO3JldHVybiBzLmZvckVhY2godGhpcywocixuKT0+e3IhPW51bGwmJnIhPT0hMSYmKHRbbl09ZSYmcy5pc0FycmF5KHIpP3Iuam9pbigiLCAiKTpyKX0pLHR9W1N5bWJvbC5pdGVyYXRvcl0oKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSlbU3ltYm9sLml0ZXJhdG9yXSgpfXRvU3RyaW5nKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpLm1hcCgoW2UsdF0pPT5lKyI6ICIrdCkuam9pbihgCmApfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0aGlzP2U6bmV3IHRoaXMoZSl9c3RhdGljIGNvbmNhdChlLC4uLnQpe2xldCByPW5ldyB0aGlzKGUpO3JldHVybiB0LmZvckVhY2gobj0+ci5zZXQobikpLHJ9c3RhdGljIGFjY2Vzc29yKGUpe2xldCByPSh0aGlzW3dlXT10aGlzW3dlXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLG49dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gaShvKXtsZXQgQz1BQShvKTtyW0NdfHwoQ3IobixvKSxyW0NdPSEwKX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHRoaXN9fTt2LmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtzLnJlZHVjZURlc2NyaXB0b3JzKHYucHJvdG90eXBlLCh7dmFsdWU6QX0sZSk9PntsZXQgdD1lWzBdLnRvVXBwZXJDYXNlKCkrZS5zbGljZSgxKTtyZXR1cm57Z2V0OigpPT5BLHNldChyKXt0aGlzW3RdPXJ9fX0pO3MuZnJlZXplTWV0aG9kcyh2KTt2YXIgYj12O2Z1bmN0aW9uIGVBKEEsZSl7bGV0IHQ9dGhpc3x8SyxyPWV8fHQsbj1iLmZyb20oci5oZWFkZXJzKSxpPXIuZGF0YTtyZXR1cm4gcy5mb3JFYWNoKEEsZnVuY3Rpb24oQyl7aT1DLmNhbGwodCxpLG4ubm9ybWFsaXplKCksZT9lLnN0YXR1czp2b2lkIDApfSksbi5ub3JtYWxpemUoKSxpfWZ1bmN0aW9uIHRBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9ZnVuY3Rpb24gRGUoQSxlLHQpe1EuY2FsbCh0aGlzLEE/PyJjYW5jZWxlZCIsUS5FUlJfQ0FOQ0VMRUQsZSx0KSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IifXMuaW5oZXJpdHMoRGUsUSx7X19DQU5DRUxfXzohMH0pO3ZhciBMPURlO2Z1bmN0aW9uIFRBKEEsZSx0KXtsZXQgcj10LmNvbmZpZy52YWxpZGF0ZVN0YXR1czshdC5zdGF0dXN8fCFyfHxyKHQuc3RhdHVzKT9BKHQpOmUobmV3IFEoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIit0LnN0YXR1cyxbUS5FUlJfQkFEX1JFUVVFU1QsUS5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKHQuc3RhdHVzLzEwMCktNF0sdC5jb25maWcsdC5yZXF1ZXN0LHQpKX12YXIgU2U9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LHIsbixpLG8sQyl7bGV0IEU9W107RS5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChyKSkscy5pc051bWJlcihuKSYmRS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUobikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmRS5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhvKSYmRS5wdXNoKCJkb21haW49IitvKSxDPT09ITAmJkUucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPUUuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgcj1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xccyopKCIrdCsiKT0oW147XSopIikpO3JldHVybiByP2RlY29kZVVSSUNvbXBvbmVudChyWzNdKTpudWxsfSxyZW1vdmU6ZnVuY3Rpb24odCl7dGhpcy53cml0ZSh0LCIiLERhdGUubm93KCktODY0ZTUpfX19KCk6ZnVuY3Rpb24oKXtyZXR1cm57d3JpdGU6ZnVuY3Rpb24oKXt9LHJlYWQ6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbH0scmVtb3ZlOmZ1bmN0aW9uKCl7fX19KCk7ZnVuY3Rpb24geEEoQSl7cmV0dXJuL14oW2Etel1bYS16XGQrXC0uXSo6KT9cL1wvL2kudGVzdChBKX1mdW5jdGlvbiBQQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXC8rJC8sIiIpKyIvIitlLnJlcGxhY2UoL15cLysvLCIiKTpBfWZ1bmN0aW9uIHJBKEEsZSl7cmV0dXJuIEEmJiF4QShlKT9QQShBLGUpOmV9dmFyIGJlPUQuaXNTdGFuZGFyZEJyb3dzZXJFbnY/ZnVuY3Rpb24oKXtsZXQgZT0vKG1zaWV8dHJpZGVudCkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpLHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpLHI7ZnVuY3Rpb24gbihpKXtsZXQgbz1pO3JldHVybiBlJiYodC5zZXRBdHRyaWJ1dGUoImhyZWYiLG8pLG89dC5ocmVmKSx0LnNldEF0dHJpYnV0ZSgiaHJlZiIsbykse2hyZWY6dC5ocmVmLHByb3RvY29sOnQucHJvdG9jb2w/dC5wcm90b2NvbC5yZXBsYWNlKC86JC8sIiIpOiIiLGhvc3Q6dC5ob3N0LHNlYXJjaDp0LnNlYXJjaD90LnNlYXJjaC5yZXBsYWNlKC9eXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiMvLCIiKToiIixob3N0bmFtZTp0Lmhvc3RuYW1lLHBvcnQ6dC5wb3J0LHBhdGhuYW1lOnQucGF0aG5hbWUuY2hhckF0KDApPT09Ii8iP3QucGF0aG5hbWU6Ii8iK3QucGF0aG5hbWV9fXJldHVybiByPW4od2luZG93LmxvY2F0aW9uLmhyZWYpLGZ1bmN0aW9uKG8pe2xldCBDPXMuaXNTdHJpbmcobyk/bihvKTpvO3JldHVybiBDLnByb3RvY29sPT09ci5wcm90b2NvbCYmQy5ob3N0PT09ci5ob3N0fX0oKTpmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiEwfX0oKTtmdW5jdGlvbiBNQShBKXtsZXQgZT0vXihbLStcd117MSwyNX0pKDo/XC9cL3w6KS8uZXhlYyhBKTtyZXR1cm4gZSYmZVsxXXx8IiJ9ZnVuY3Rpb24gQnIoQSxlKXtBPUF8fDEwO2xldCB0PW5ldyBBcnJheShBKSxyPW5ldyBBcnJheShBKSxuPTAsaT0wLG87cmV0dXJuIGU9ZSE9PXZvaWQgMD9lOjFlMyxmdW5jdGlvbihFKXtsZXQgST1EYXRlLm5vdygpLGE9cltpXTtvfHwobz1JKSx0W25dPUUscltuXT1JO2xldCBjPWksQj0wO2Zvcig7YyE9PW47KUIrPXRbYysrXSxjPWMlQTtpZihuPShuKzEpJUEsbj09PWkmJihpPShpKzEpJUEpLEktbzxlKXJldHVybjtsZXQgZz1hJiZJLWE7cmV0dXJuIGc/TWF0aC5yb3VuZChCKjFlMy9nKTp2b2lkIDB9fXZhciBGZT1CcjtmdW5jdGlvbiBSZShBLGUpe2xldCB0PTAscj1GZSg1MCwyNTApO3JldHVybiBuPT57bGV0IGk9bi5sb2FkZWQsbz1uLmxlbmd0aENvbXB1dGFibGU/bi50b3RhbDp2b2lkIDAsQz1pLXQsRT1yKEMpLEk9aTw9bzt0PWk7bGV0IGE9e2xvYWRlZDppLHRvdGFsOm8scHJvZ3Jlc3M6bz9pL286dm9pZCAwLGJ5dGVzOkMscmF0ZTpFfHx2b2lkIDAsZXN0aW1hdGVkOkUmJm8mJkk/KG8taSkvRTp2b2lkIDAsZXZlbnQ6bn07YVtlPyJkb3dubG9hZCI6InVwbG9hZCJdPSEwLEEoYSl9fXZhciBscj10eXBlb2YgWE1MSHR0cFJlcXVlc3Q8InUiLGtlPWxyJiZmdW5jdGlvbihBKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24odCxyKXtsZXQgbj1BLmRhdGEsaT1iLmZyb20oQS5oZWFkZXJzKS5ub3JtYWxpemUoKSxvPUEucmVzcG9uc2VUeXBlLEM7ZnVuY3Rpb24gRSgpe0EuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUoQyksQS5zaWduYWwmJkEuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixDKX1sZXQgSTtzLmlzRm9ybURhdGEobikmJihELmlzU3RhbmRhcmRCcm93c2VyRW52fHxELmlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52P2kuc2V0Q29udGVudFR5cGUoITEpOmkuZ2V0Q29udGVudFR5cGUoL15ccyptdWx0aXBhcnRcL2Zvcm0tZGF0YS8pP3MuaXNTdHJpbmcoST1pLmdldENvbnRlbnRUeXBlKCkpJiZpLnNldENvbnRlbnRUeXBlKEkucmVwbGFjZSgvXlxzKihtdWx0aXBhcnRcL2Zvcm0tZGF0YSk7Ky8sIiQxIikpOmkuc2V0Q29udGVudFR5cGUoIm11bHRpcGFydC9mb3JtLWRhdGEiKSk7bGV0IGE9bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IGw9QS5hdXRoLnVzZXJuYW1lfHwiIixmPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EobCsiOiIrZikpfWxldCBjPXJBKEEuYmFzZVVSTCxBLnVybCk7YS5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksJChjLEEucGFyYW1zLEEucGFyYW1zU2VyaWFsaXplciksITApLGEudGltZW91dD1BLnRpbWVvdXQ7ZnVuY3Rpb24gQigpe2lmKCFhKXJldHVybjtsZXQgbD1iLmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBhJiZhLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxwPXtkYXRhOiFvfHxvPT09InRleHQifHxvPT09Impzb24iP2EucmVzcG9uc2VUZXh0OmEucmVzcG9uc2Usc3RhdHVzOmEuc3RhdHVzLHN0YXR1c1RleHQ6YS5zdGF0dXNUZXh0LGhlYWRlcnM6bCxjb25maWc6QSxyZXF1ZXN0OmF9O1RBKGZ1bmN0aW9uKHUpe3QodSksRSgpfSxmdW5jdGlvbih1KXtyKHUpLEUoKX0scCksYT1udWxsfWlmKCJvbmxvYWRlbmQiaW4gYT9hLm9ubG9hZGVuZD1COmEub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IWF8fGEucmVhZHlTdGF0ZSE9PTR8fGEuc3RhdHVzPT09MCYmIShhLnJlc3BvbnNlVVJMJiZhLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChCKX0sYS5vbmFib3J0PWZ1bmN0aW9uKCl7YSYmKHIobmV3IFEoIlJlcXVlc3QgYWJvcnRlZCIsUS5FQ09OTkFCT1JURUQsQSxhKSksYT1udWxsKX0sYS5vbmVycm9yPWZ1bmN0aW9uKCl7cihuZXcgUSgiTmV0d29yayBFcnJvciIsUS5FUlJfTkVUV09SSyxBLGEpKSxhPW51bGx9LGEub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IGY9QS50aW1lb3V0PyJ0aW1lb3V0IG9mICIrQS50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLHA9QS50cmFuc2l0aW9uYWx8fEJBO0EudGltZW91dEVycm9yTWVzc2FnZSYmKGY9QS50aW1lb3V0RXJyb3JNZXNzYWdlKSxyKG5ldyBRKGYscC5jbGFyaWZ5VGltZW91dEVycm9yP1EuRVRJTUVET1VUOlEuRUNPTk5BQk9SVEVELEEsYSkpLGE9bnVsbH0sRC5pc1N0YW5kYXJkQnJvd3NlckVudil7bGV0IGw9YmUoYykmJkEueHNyZkNvb2tpZU5hbWUmJlNlLnJlYWQoQS54c3JmQ29va2llTmFtZSk7bCYmaS5zZXQoQS54c3JmSGVhZGVyTmFtZSxsKX1uPT09dm9pZCAwJiZpLnNldENvbnRlbnRUeXBlKG51bGwpLCJzZXRSZXF1ZXN0SGVhZGVyImluIGEmJnMuZm9yRWFjaChpLnRvSlNPTigpLGZ1bmN0aW9uKGYscCl7YS5zZXRSZXF1ZXN0SGVhZGVyKHAsZil9KSxzLmlzVW5kZWZpbmVkKEEud2l0aENyZWRlbnRpYWxzKXx8KGEud2l0aENyZWRlbnRpYWxzPSEhQS53aXRoQ3JlZGVudGlhbHMpLG8mJm8hPT0ianNvbiImJihhLnJlc3BvbnNlVHlwZT1BLnJlc3BvbnNlVHlwZSksdHlwZW9mIEEub25Eb3dubG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZhLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixSZShBLm9uRG93bmxvYWRQcm9ncmVzcywhMCkpLHR5cGVvZiBBLm9uVXBsb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJmEudXBsb2FkJiZhLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsUmUoQS5vblVwbG9hZFByb2dyZXNzKSksKEEuY2FuY2VsVG9rZW58fEEuc2lnbmFsKSYmKEM9bD0+e2EmJihyKCFsfHxsLnR5cGU/bmV3IEwobnVsbCxBLGEpOmwpLGEuYWJvcnQoKSxhPW51bGwpfSxBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnN1YnNjcmliZShDKSxBLnNpZ25hbCYmKEEuc2lnbmFsLmFib3J0ZWQ/QygpOkEuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixDKSkpO2xldCBnPU1BKGMpO2lmKGcmJkQucHJvdG9jb2xzLmluZGV4T2YoZyk9PT0tMSl7cihuZXcgUSgiVW5zdXBwb3J0ZWQgcHJvdG9jb2wgIitnKyI6IixRLkVSUl9CQURfUkVRVUVTVCxBKSk7cmV0dXJufWEuc2VuZChufHxudWxsKX0pfTt2YXIgSkE9e2h0dHA6Z0EseGhyOmtlfTtzLmZvckVhY2goSkEsKEEsZSk9PntpZihBKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsIm5hbWUiLHt2YWx1ZTplfSl9Y2F0Y2h7fU9iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJhZGFwdGVyTmFtZSIse3ZhbHVlOmV9KX19KTt2YXIgVWU9QT0+YC0gJHtBfWAsY3I9QT0+cy5pc0Z1bmN0aW9uKEEpfHxBPT09bnVsbHx8QT09PSExLEVBPXtnZXRBZGFwdGVyOkE9PntBPXMuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsdCxyLG49e307Zm9yKGxldCBpPTA7aTxlO2krKyl7dD1BW2ldO2xldCBvO2lmKHI9dCwhY3IodCkmJihyPUpBWyhvPVN0cmluZyh0KSkudG9Mb3dlckNhc2UoKV0scj09PXZvaWQgMCkpdGhyb3cgbmV3IFEoYFVua25vd24gYWRhcHRlciAnJHtvfSdgKTtpZihyKWJyZWFrO25bb3x8IiMiK2ldPXJ9aWYoIXIpe2xldCBpPU9iamVjdC5lbnRyaWVzKG4pLm1hcCgoW0MsRV0pPT5gYWRhcHRlciAke0N9IGArKEU9PT0hMT8iaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZW52aXJvbm1lbnQiOiJpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZCIpKSxvPWU/aS5sZW5ndGg+MT9gc2luY2UgOgpgK2kubWFwKFVlKS5qb2luKGAKYCk6IiAiK1VlKGlbMF0pOiJhcyBubyBhZGFwdGVyIHNwZWNpZmllZCI7dGhyb3cgbmV3IFEoIlRoZXJlIGlzIG5vIHN1aXRhYmxlIGFkYXB0ZXIgdG8gZGlzcGF0Y2ggdGhlIHJlcXVlc3QgIitvLCJFUlJfTk9UX1NVUFBPUlQiKX1yZXR1cm4gcn0sYWRhcHRlcnM6SkF9O2Z1bmN0aW9uIEhBKEEpe2lmKEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLEEuc2lnbmFsJiZBLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyBMKG51bGwsQSl9ZnVuY3Rpb24gZkEoQSl7cmV0dXJuIEhBKEEpLEEuaGVhZGVycz1iLmZyb20oQS5oZWFkZXJzKSxBLmRhdGE9ZUEuY2FsbChBLEEudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKEEubWV0aG9kKSE9PS0xJiZBLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLEVBLmdldEFkYXB0ZXIoQS5hZGFwdGVyfHxLLmFkYXB0ZXIpKEEpLnRoZW4oZnVuY3Rpb24ocil7cmV0dXJuIEhBKEEpLHIuZGF0YT1lQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxyKSxyLmhlYWRlcnM9Yi5mcm9tKHIuaGVhZGVycykscn0sZnVuY3Rpb24ocil7cmV0dXJuIHRBKHIpfHwoSEEoQSksciYmci5yZXNwb25zZSYmKHIucmVzcG9uc2UuZGF0YT1lQS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxyLnJlc3BvbnNlKSxyLnJlc3BvbnNlLmhlYWRlcnM9Yi5mcm9tKHIucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChyKX0pfXZhciBOZT1BPT5BIGluc3RhbmNlb2YgYj9BLnRvSlNPTigpOkE7ZnVuY3Rpb24gTyhBLGUpe2U9ZXx8e307bGV0IHQ9e307ZnVuY3Rpb24gcihJLGEsYyl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChJKSYmcy5pc1BsYWluT2JqZWN0KGEpP3MubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6Y30sSSxhKTpzLmlzUGxhaW5PYmplY3QoYSk/cy5tZXJnZSh7fSxhKTpzLmlzQXJyYXkoYSk/YS5zbGljZSgpOmF9ZnVuY3Rpb24gbihJLGEsYyl7aWYocy5pc1VuZGVmaW5lZChhKSl7aWYoIXMuaXNVbmRlZmluZWQoSSkpcmV0dXJuIHIodm9pZCAwLEksYyl9ZWxzZSByZXR1cm4gcihJLGEsYyl9ZnVuY3Rpb24gaShJLGEpe2lmKCFzLmlzVW5kZWZpbmVkKGEpKXJldHVybiByKHZvaWQgMCxhKX1mdW5jdGlvbiBvKEksYSl7aWYocy5pc1VuZGVmaW5lZChhKSl7aWYoIXMuaXNVbmRlZmluZWQoSSkpcmV0dXJuIHIodm9pZCAwLEkpfWVsc2UgcmV0dXJuIHIodm9pZCAwLGEpfWZ1bmN0aW9uIEMoSSxhLGMpe2lmKGMgaW4gZSlyZXR1cm4gcihJLGEpO2lmKGMgaW4gQSlyZXR1cm4gcih2b2lkIDAsSSl9bGV0IEU9e3VybDppLG1ldGhvZDppLGRhdGE6aSxiYXNlVVJMOm8sdHJhbnNmb3JtUmVxdWVzdDpvLHRyYW5zZm9ybVJlc3BvbnNlOm8scGFyYW1zU2VyaWFsaXplcjpvLHRpbWVvdXQ6byx0aW1lb3V0TWVzc2FnZTpvLHdpdGhDcmVkZW50aWFsczpvLGFkYXB0ZXI6byxyZXNwb25zZVR5cGU6byx4c3JmQ29va2llTmFtZTpvLHhzcmZIZWFkZXJOYW1lOm8sb25VcGxvYWRQcm9ncmVzczpvLG9uRG93bmxvYWRQcm9ncmVzczpvLGRlY29tcHJlc3M6byxtYXhDb250ZW50TGVuZ3RoOm8sbWF4Qm9keUxlbmd0aDpvLGJlZm9yZVJlZGlyZWN0Om8sdHJhbnNwb3J0Om8saHR0cEFnZW50Om8saHR0cHNBZ2VudDpvLGNhbmNlbFRva2VuOm8sc29ja2V0UGF0aDpvLHJlc3BvbnNlRW5jb2Rpbmc6byx2YWxpZGF0ZVN0YXR1czpDLGhlYWRlcnM6KEksYSk9Pm4oTmUoSSksTmUoYSksITApfTtyZXR1cm4gcy5mb3JFYWNoKE9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30sQSxlKSksZnVuY3Rpb24oYSl7bGV0IGM9RVthXXx8bixCPWMoQVthXSxlW2FdLGEpO3MuaXNVbmRlZmluZWQoQikmJmMhPT1DfHwodFthXT1CKX0pLHR9dmFyIFFBPSIxLjYuMCI7dmFyIFlBPXt9O1sib2JqZWN0IiwiYm9vbGVhbiIsIm51bWJlciIsImZ1bmN0aW9uIiwic3RyaW5nIiwic3ltYm9sIl0uZm9yRWFjaCgoQSxlKT0+e1lBW0FdPWZ1bmN0aW9uKHIpe3JldHVybiB0eXBlb2Ygcj09PUF8fCJhIisoZTwxPyJuICI6IiAiKStBfX0pO3ZhciBPZT17fTtZQS50cmFuc2l0aW9uYWw9ZnVuY3Rpb24oZSx0LHIpe2Z1bmN0aW9uIG4oaSxvKXtyZXR1cm4iW0F4aW9zIHYiK1FBKyJdIFRyYW5zaXRpb25hbCBvcHRpb24gJyIraSsiJyIrbysocj8iLiAiK3I6IiIpfXJldHVybihpLG8sQyk9PntpZihlPT09ITEpdGhyb3cgbmV3IFEobihvLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKHQ/IiBpbiAiK3Q6IiIpKSxRLkVSUl9ERVBSRUNBVEVEKTtyZXR1cm4gdCYmIU9lW29dJiYoT2Vbb109ITAsY29uc29sZS53YXJuKG4obywiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrdCsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSxlP2UoaSxvLEMpOiEwfX07ZnVuY3Rpb24gRXIoQSxlLHQpe2lmKHR5cGVvZiBBIT0ib2JqZWN0Iil0aHJvdyBuZXcgUSgib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIsUS5FUlJfQkFEX09QVElPTl9WQUxVRSk7bGV0IHI9T2JqZWN0LmtleXMoQSksbj1yLmxlbmd0aDtmb3IoO24tLSA+MDspe2xldCBpPXJbbl0sbz1lW2ldO2lmKG8pe2xldCBDPUFbaV0sRT1DPT09dm9pZCAwfHxvKEMsaSxBKTtpZihFIT09ITApdGhyb3cgbmV3IFEoIm9wdGlvbiAiK2krIiBtdXN0IGJlICIrRSxRLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgbmV3IFEoIlVua25vd24gb3B0aW9uICIraSxRLkVSUl9CQURfT1BUSU9OKX19dmFyIHVBPXthc3NlcnRPcHRpb25zOkVyLHZhbGlkYXRvcnM6WUF9O3ZhciBUPXVBLnZhbGlkYXRvcnMsaj1jbGFzc3tjb25zdHJ1Y3RvcihlKXt0aGlzLmRlZmF1bHRzPWUsdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IE5BLHJlc3BvbnNlOm5ldyBOQX19cmVxdWVzdChlLHQpe3R5cGVvZiBlPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1lKTp0PWV8fHt9LHQ9Tyh0aGlzLmRlZmF1bHRzLHQpO2xldHt0cmFuc2l0aW9uYWw6cixwYXJhbXNTZXJpYWxpemVyOm4saGVhZGVyczppfT10O3IhPT12b2lkIDAmJnVBLmFzc2VydE9wdGlvbnMocix7c2lsZW50SlNPTlBhcnNpbmc6VC50cmFuc2l0aW9uYWwoVC5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpULnRyYW5zaXRpb25hbChULmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6VC50cmFuc2l0aW9uYWwoVC5ib29sZWFuKX0sITEpLG4hPW51bGwmJihzLmlzRnVuY3Rpb24obik/dC5wYXJhbXNTZXJpYWxpemVyPXtzZXJpYWxpemU6bn06dUEuYXNzZXJ0T3B0aW9ucyhuLHtlbmNvZGU6VC5mdW5jdGlvbixzZXJpYWxpemU6VC5mdW5jdGlvbn0sITApKSx0Lm1ldGhvZD0odC5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgbz1pJiZzLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKTtpJiZzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sbD0+e2RlbGV0ZSBpW2xdfSksdC5oZWFkZXJzPWIuY29uY2F0KG8saSk7bGV0IEM9W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7dHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITF8fChFPUUmJmYuc3luY2hyb25vdXMsQy51bnNoaWZ0KGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpKX0pO2xldCBJPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZil7SS5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IGEsYz0wLEI7aWYoIUUpe2xldCBsPVtmQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKGwudW5zaGlmdC5hcHBseShsLEMpLGwucHVzaC5hcHBseShsLEkpLEI9bC5sZW5ndGgsYT1Qcm9taXNlLnJlc29sdmUodCk7YzxCOylhPWEudGhlbihsW2MrK10sbFtjKytdKTtyZXR1cm4gYX1CPUMubGVuZ3RoO2xldCBnPXQ7Zm9yKGM9MDtjPEI7KXtsZXQgbD1DW2MrK10sZj1DW2MrK107dHJ5e2c9bChnKX1jYXRjaChwKXtmLmNhbGwodGhpcyxwKTticmVha319dHJ5e2E9ZkEuY2FsbCh0aGlzLGcpfWNhdGNoKGwpe3JldHVybiBQcm9taXNlLnJlamVjdChsKX1mb3IoYz0wLEI9SS5sZW5ndGg7YzxCOylhPWEudGhlbihJW2MrK10sSVtjKytdKTtyZXR1cm4gYX1nZXRVcmkoZSl7ZT1PKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9ckEoZS5iYXNlVVJMLGUudXJsKTtyZXR1cm4gJCh0LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplcil9fTtzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKGUpe2oucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQscil7cmV0dXJuIHRoaXMucmVxdWVzdChPKHJ8fHt9LHttZXRob2Q6ZSx1cmw6dCxkYXRhOihyfHx7fSkuZGF0YX0pKX19KTtzLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHIpe3JldHVybiBmdW5jdGlvbihpLG8sQyl7cmV0dXJuIHRoaXMucmVxdWVzdChPKEN8fHt9LHttZXRob2Q6ZSxoZWFkZXJzOnI/eyJDb250ZW50LVR5cGUiOiJtdWx0aXBhcnQvZm9ybS1kYXRhIn06e30sdXJsOmksZGF0YTpvfSkpfX1qLnByb3RvdHlwZVtlXT10KCksai5wcm90b3R5cGVbZSsiRm9ybSJdPXQoITApfSk7dmFyIG5BPWo7dmFyIHFBPWNsYXNzIEF7Y29uc3RydWN0b3IoZSl7aWYodHlwZW9mIGUhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO2xldCB0O3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihpKXt0PWl9KTtsZXQgcj10aGlzO3RoaXMucHJvbWlzZS50aGVuKG49PntpZighci5fbGlzdGVuZXJzKXJldHVybjtsZXQgaT1yLl9saXN0ZW5lcnMubGVuZ3RoO2Zvcig7aS0tID4wOylyLl9saXN0ZW5lcnNbaV0obik7ci5fbGlzdGVuZXJzPW51bGx9KSx0aGlzLnByb21pc2UudGhlbj1uPT57bGV0IGksbz1uZXcgUHJvbWlzZShDPT57ci5zdWJzY3JpYmUoQyksaT1DfSkudGhlbihuKTtyZXR1cm4gby5jYW5jZWw9ZnVuY3Rpb24oKXtyLnVuc3Vic2NyaWJlKGkpfSxvfSxlKGZ1bmN0aW9uKGksbyxDKXtyLnJlYXNvbnx8KHIucmVhc29uPW5ldyBMKGksbyxDKSx0KHIucmVhc29uKSl9KX10aHJvd0lmUmVxdWVzdGVkKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259c3Vic2NyaWJlKGUpe2lmKHRoaXMucmVhc29uKXtlKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKGUpOnRoaXMuX2xpc3RlbmVycz1bZV19dW5zdWJzY3JpYmUoZSl7aWYoIXRoaXMuX2xpc3RlbmVycylyZXR1cm47bGV0IHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoZSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9c3RhdGljIHNvdXJjZSgpe2xldCBlO3JldHVybnt0b2tlbjpuZXcgQShmdW5jdGlvbihuKXtlPW59KSxjYW5jZWw6ZX19fSxHZT1xQTtmdW5jdGlvbiBLQShBKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIEEuYXBwbHkobnVsbCx0KX19ZnVuY3Rpb24gdkEoQSl7cmV0dXJuIHMuaXNPYmplY3QoQSkmJkEuaXNBeGlvc0Vycm9yPT09ITB9dmFyIGpBPXtDb250aW51ZToxMDAsU3dpdGNoaW5nUHJvdG9jb2xzOjEwMSxQcm9jZXNzaW5nOjEwMixFYXJseUhpbnRzOjEwMyxPazoyMDAsQ3JlYXRlZDoyMDEsQWNjZXB0ZWQ6MjAyLE5vbkF1dGhvcml0YXRpdmVJbmZvcm1hdGlvbjoyMDMsTm9Db250ZW50OjIwNCxSZXNldENvbnRlbnQ6MjA1LFBhcnRpYWxDb250ZW50OjIwNixNdWx0aVN0YXR1czoyMDcsQWxyZWFkeVJlcG9ydGVkOjIwOCxJbVVzZWQ6MjI2LE11bHRpcGxlQ2hvaWNlczozMDAsTW92ZWRQZXJtYW5lbnRseTozMDEsRm91bmQ6MzAyLFNlZU90aGVyOjMwMyxOb3RNb2RpZmllZDozMDQsVXNlUHJveHk6MzA1LFVudXNlZDozMDYsVGVtcG9yYXJ5UmVkaXJlY3Q6MzA3LFBlcm1hbmVudFJlZGlyZWN0OjMwOCxCYWRSZXF1ZXN0OjQwMCxVbmF1dGhvcml6ZWQ6NDAxLFBheW1lbnRSZXF1aXJlZDo0MDIsRm9yYmlkZGVuOjQwMyxOb3RGb3VuZDo0MDQsTWV0aG9kTm90QWxsb3dlZDo0MDUsTm90QWNjZXB0YWJsZTo0MDYsUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkOjQwNyxSZXF1ZXN0VGltZW91dDo0MDgsQ29uZmxpY3Q6NDA5LEdvbmU6NDEwLExlbmd0aFJlcXVpcmVkOjQxMSxQcmVjb25kaXRpb25GYWlsZWQ6NDEyLFBheWxvYWRUb29MYXJnZTo0MTMsVXJpVG9vTG9uZzo0MTQsVW5zdXBwb3J0ZWRNZWRpYVR5cGU6NDE1LFJhbmdlTm90U2F0aXNmaWFibGU6NDE2LEV4cGVjdGF0aW9uRmFpbGVkOjQxNyxJbUFUZWFwb3Q6NDE4LE1pc2RpcmVjdGVkUmVxdWVzdDo0MjEsVW5wcm9jZXNzYWJsZUVudGl0eTo0MjIsTG9ja2VkOjQyMyxGYWlsZWREZXBlbmRlbmN5OjQyNCxUb29FYXJseTo0MjUsVXBncmFkZVJlcXVpcmVkOjQyNixQcmVjb25kaXRpb25SZXF1aXJlZDo0MjgsVG9vTWFueVJlcXVlc3RzOjQyOSxSZXF1ZXN0SGVhZGVyRmllbGRzVG9vTGFyZ2U6NDMxLFVuYXZhaWxhYmxlRm9yTGVnYWxSZWFzb25zOjQ1MSxJbnRlcm5hbFNlcnZlckVycm9yOjUwMCxOb3RJbXBsZW1lbnRlZDo1MDEsQmFkR2F0ZXdheTo1MDIsU2VydmljZVVuYXZhaWxhYmxlOjUwMyxHYXRld2F5VGltZW91dDo1MDQsSHR0cFZlcnNpb25Ob3RTdXBwb3J0ZWQ6NTA1LFZhcmlhbnRBbHNvTmVnb3RpYXRlczo1MDYsSW5zdWZmaWNpZW50U3RvcmFnZTo1MDcsTG9vcERldGVjdGVkOjUwOCxOb3RFeHRlbmRlZDo1MTAsTmV0d29ya0F1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NTExfTtPYmplY3QuZW50cmllcyhqQSkuZm9yRWFjaCgoW0EsZV0pPT57akFbZV09QX0pO3ZhciBMZT1qQTtmdW5jdGlvbiBUZShBKXtsZXQgZT1uZXcgbkEoQSksdD1WKG5BLnByb3RvdHlwZS5yZXF1ZXN0LGUpO3JldHVybiBzLmV4dGVuZCh0LG5BLnByb3RvdHlwZSxlLHthbGxPd25LZXlzOiEwfSkscy5leHRlbmQodCxlLG51bGwse2FsbE93bktleXM6ITB9KSx0LmNyZWF0ZT1mdW5jdGlvbihuKXtyZXR1cm4gVGUoTyhBLG4pKX0sdH12YXIgbT1UZShLKTttLkF4aW9zPW5BO20uQ2FuY2VsZWRFcnJvcj1MO20uQ2FuY2VsVG9rZW49R2U7bS5pc0NhbmNlbD10QTttLlZFUlNJT049UUE7bS50b0Zvcm1EYXRhPUc7bS5BeGlvc0Vycm9yPVE7bS5DYW5jZWw9bS5DYW5jZWxlZEVycm9yO20uYWxsPWZ1bmN0aW9uKGUpe3JldHVybiBQcm9taXNlLmFsbChlKX07bS5zcHJlYWQ9S0E7bS5pc0F4aW9zRXJyb3I9dkE7bS5tZXJnZUNvbmZpZz1PO20uQXhpb3NIZWFkZXJzPWI7bS5mb3JtVG9KU09OPUE9PmxBKHMuaXNIVE1MRm9ybShBKT9uZXcgRm9ybURhdGEoQSk6QSk7bS5nZXRBZGFwdGVyPUVBLmdldEFkYXB0ZXI7bS5IdHRwU3RhdHVzQ29kZT1MZTttLmRlZmF1bHQ9bTt2YXIgTT1tO3ZhcntBeGlvczpVbyxBeGlvc0Vycm9yOk5vLENhbmNlbGVkRXJyb3I6T28saXNDYW5jZWw6R28sQ2FuY2VsVG9rZW46TG8sVkVSU0lPTjpUbyxhbGw6eG8sQ2FuY2VsOlBvLGlzQXhpb3NFcnJvcjpNbyxzcHJlYWQ6Sm8sdG9Gb3JtRGF0YTpIbyxBeGlvc0hlYWRlcnM6WW8sSHR0cFN0YXR1c0NvZGU6cW8sZm9ybVRvSlNPTjpLbyxnZXRBZGFwdGVyOnZvLG1lcmdlQ29uZmlnOmpvfT1NO3ZhciBQZT1TeW1ib2woIkNvbWxpbmsucHJveHkiKSxmcj1TeW1ib2woIkNvbWxpbmsuZW5kcG9pbnQiKSx6QT1TeW1ib2woIkNvbWxpbmsucmVsZWFzZVByb3h5IiksV0E9U3ltYm9sKCJDb21saW5rLmZpbmFsaXplciIpLHBBPVN5bWJvbCgiQ29tbGluay50aHJvd24iKSxNZT1BPT50eXBlb2YgQT09Im9iamVjdCImJkEhPT1udWxsfHx0eXBlb2YgQT09ImZ1bmN0aW9uIixRcj17Y2FuSGFuZGxlOkE9Pk1lKEEpJiZBW1BlXSxzZXJpYWxpemUoQSl7bGV0e3BvcnQxOmUscG9ydDI6dH09bmV3IE1lc3NhZ2VDaGFubmVsO3JldHVybiBIZShBLGUpLFt0LFt0XV19LGRlc2VyaWFsaXplKEEpe3JldHVybiBBLnN0YXJ0KCksVkEoQSl9fSx1cj17Y2FuSGFuZGxlOkE9Pk1lKEEpJiZwQSBpbiBBLHNlcmlhbGl6ZSh7dmFsdWU6QX0pe2xldCBlO3JldHVybiBBIGluc3RhbmNlb2YgRXJyb3I/ZT17aXNFcnJvcjohMCx2YWx1ZTp7bWVzc2FnZTpBLm1lc3NhZ2UsbmFtZTpBLm5hbWUsc3RhY2s6QS5zdGFja319OmU9e2lzRXJyb3I6ITEsdmFsdWU6QX0sW2UsW11dfSxkZXNlcmlhbGl6ZShBKXt0aHJvdyBBLmlzRXJyb3I/T2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoQS52YWx1ZS5tZXNzYWdlKSxBLnZhbHVlKTpBLnZhbHVlfX0sSmU9bmV3IE1hcChbWyJwcm94eSIsUXJdLFsidGhyb3ciLHVyXV0pO2Z1bmN0aW9uIGRyKEEsZSl7Zm9yKGxldCB0IG9mIEEpaWYoZT09PXR8fHQ9PT0iKiJ8fHQgaW5zdGFuY2VvZiBSZWdFeHAmJnQudGVzdChlKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBIZShBLGU9Z2xvYmFsVGhpcyx0PVsiKiJdKXtlLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIHIobil7aWYoIW58fCFuLmRhdGEpcmV0dXJuO2lmKCFkcih0LG4ub3JpZ2luKSl7Y29uc29sZS53YXJuKGBJbnZhbGlkIG9yaWdpbiAnJHtuLm9yaWdpbn0nIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6byxwYXRoOkN9PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LG4uZGF0YSksRT0obi5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChKKSxJO3RyeXtsZXQgYT1DLnNsaWNlKDAsLTEpLnJlZHVjZSgoQixnKT0+QltnXSxBKSxjPUMucmVkdWNlKChCLGcpPT5CW2ddLEEpO3N3aXRjaChvKXtjYXNlIkdFVCI6ST1jO2JyZWFrO2Nhc2UiU0VUIjphW0Muc2xpY2UoLTEpWzBdXT1KKG4uZGF0YS52YWx1ZSksST0hMDticmVhaztjYXNlIkFQUExZIjpJPWMuYXBwbHkoYSxFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBCPW5ldyBjKC4uLkUpO0k9d3IoQil9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTpCLHBvcnQyOmd9PW5ldyBNZXNzYWdlQ2hhbm5lbDtIZShBLGcpLEk9WkEoQixbQl0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6ST12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKGEpe0k9e3ZhbHVlOmEsW3BBXTowfX1Qcm9taXNlLnJlc29sdmUoSSkuY2F0Y2goYT0+KHt2YWx1ZTphLFtwQV06MH0pKS50aGVuKGE9PntsZXRbYyxCXT15QShhKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLEIpLG89PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLHIpLFllKGUpLFdBIGluIEEmJnR5cGVvZiBBW1dBXT09ImZ1bmN0aW9uIiYmQVtXQV0oKSl9KS5jYXRjaChhPT57bGV0W2MsQl09eUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtwQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LGMpLHtpZDppfSksQil9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBwcihBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiBZZShBKXtwcihBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIFZBKEEsZSl7cmV0dXJuIF9BKEEsW10sZSl9ZnVuY3Rpb24gZEEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIHFlKEEpe3JldHVybiBXKEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e1llKEEpfSl9dmFyIG1BPW5ldyBXZWFrTWFwLGhBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPShtQS5nZXQoQSl8fDApLTE7bUEuc2V0KEEsZSksZT09PTAmJnFlKEEpfSk7ZnVuY3Rpb24gbXIoQSxlKXtsZXQgdD0obUEuZ2V0KGUpfHwwKSsxO21BLnNldChlLHQpLGhBJiZoQS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gaHIoQSl7aEEmJmhBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gX0EoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgcj0hMSxuPW5ldyBQcm94eSh0LHtnZXQoaSxvKXtpZihkQShyKSxvPT09ekEpcmV0dXJuKCk9PntocihuKSxxZShBKSxyPSEwfTtpZihvPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9Pm59O2xldCBDPVcoQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKEU9PkUudG9TdHJpbmcoKSl9KS50aGVuKEopO3JldHVybiBDLnRoZW4uYmluZChDKX1yZXR1cm4gX0EoQSxbLi4uZSxvXSl9LHNldChpLG8sQyl7ZEEocik7bGV0W0UsSV09eUEoQyk7cmV0dXJuIFcoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLG9dLm1hcChhPT5hLnRvU3RyaW5nKCkpLHZhbHVlOkV9LEkpLnRoZW4oSil9LGFwcGx5KGksbyxDKXtkQShyKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1mcilyZXR1cm4gVyhBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKEopO2lmKEU9PT0iYmluZCIpcmV0dXJuIF9BKEEsZS5zbGljZSgwLC0xKSk7bGV0W0ksYV09eGUoQyk7cmV0dXJuIFcoQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoYz0+Yy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6SX0sYSkudGhlbihKKX0sY29uc3RydWN0KGksbyl7ZEEocik7bGV0W0MsRV09eGUobyk7cmV0dXJuIFcoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKEk9PkkudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0OkN9LEUpLnRoZW4oSil9fSk7cmV0dXJuIG1yKG4sQSksbn1mdW5jdGlvbiB5cihBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiB4ZShBKXtsZXQgZT1BLm1hcCh5QSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLHlyKGUubWFwKHQ9PnRbMV0pKV19dmFyIEtlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIFpBKEEsZSl7cmV0dXJuIEtlLnNldChBLGUpLEF9ZnVuY3Rpb24gd3IoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W1BlXTohMH0pfWZ1bmN0aW9uIHlBKEEpe2ZvcihsZXRbZSx0XW9mIEplKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbcixuXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpyfSxuXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sS2UuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gSihBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBKZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIFcoQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShyPT57bGV0IG49RHIoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkobyl7IW8uZGF0YXx8IW8uZGF0YS5pZHx8by5kYXRhLmlkIT09bnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSkscihvLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOm59LGUpLHQpfSl9ZnVuY3Rpb24gRHIoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIGplKEEpe2xldCBlPVZBKEEpLHQ9QTtyZXR1cm4gdC53b3JrZXJQcm94eT1lLHQub3JpZ2luYWxUZXJtaW5hdGU9dC50ZXJtaW5hdGUsdC50ZXJtaW5hdGU9KCk9Pnt0LndvcmtlclByb3h5W3pBXSgpLHQub3JpZ2luYWxUZXJtaW5hdGUoKX0se3dvcmtlclByb3h5OmUsd29ya2VyOnR9fWFzeW5jIGZ1bmN0aW9uIFNyKEEsZSl7bGV0IHQ7aWYoQSE9bnVsbCl7bGV0IG89QTtyZXR1cm4gby53b3JrZXJQcm94eSE9PXZvaWQgMD8odD1vLndvcmtlclByb3h5LHt3b3JrZXJQcm94eTp0LHdvcmtlcjpvfSk6amUoQSl9bGV0IHI9dHlwZW9mIGU+InUiP0gucGlwZWxpbmVXb3JrZXJVcmw6ZSxuPW51bGwsaT1ILndlYldvcmtlcnNVcmw7aWYodHlwZW9mIGk8InUiKXtjb25zb2xlLndhcm4oIml0a0NvbmZpZyB3ZWJXb3JrZXJzVXJsIGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSB1c2UgcGlwZWxpbmVXb3JrZXJVcmwgd2l0aCB0aGUgZnVsbCBwYXRoIHRvIHRoZSBwaXBlbGluZSB3b3JrZXIuIik7bGV0IG89Im1pbi4iLEM9aTtpZihDLnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IEU9YXdhaXQgTS5nZXQoYCR7Q30vYnVuZGxlcy9waXBlbGluZS4ke299d29ya2VyLmpzYCx7cmVzcG9uc2VUeXBlOiJibG9iIn0pLEk9VVJMLmNyZWF0ZU9iamVjdFVSTChFLmRhdGEpO249bmV3IFdvcmtlcihJLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBuPW5ldyBXb3JrZXIoYCR7Q30vYnVuZGxlcy9waXBlbGluZS4ke299d29ya2VyLmpzYCx7dHlwZToibW9kdWxlIn0pfWVsc2UgaWYocj09PW51bGwpbj1uZXcgV29ya2VyKG5ldyBVUkwoIi4vd2ViLXdvcmtlcnMvaXRrLXdhc20tcGlwZWxpbmUud29ya2VyLmpzIixpbXBvcnQubWV0YS51cmwpLHt0eXBlOiJtb2R1bGUifSk7ZWxzZSBpZihyLnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IG89YXdhaXQgTS5nZXQocix7cmVzcG9uc2VUeXBlOiJibG9iIn0pLEM9VVJMLmNyZWF0ZU9iamVjdFVSTChvLmRhdGEpO249bmV3IFdvcmtlcihDLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBuPW5ldyBXb3JrZXIocix7dHlwZToibW9kdWxlIn0pO3JldHVybiBqZShuKX12YXIgV2U9U3I7dmFyIGJyO2Z1bmN0aW9uIF9lKCl7cmV0dXJuIGJyfXZhciBGcjtmdW5jdGlvbiB6ZSgpe3JldHVybiBGcn1mdW5jdGlvbiBScihBKXtyZXR1cm5bQS5kYXRhLEEuZGlyZWN0aW9uXX12YXIgWEE9UnI7ZnVuY3Rpb24ga3IoQSl7cmV0dXJuW0EucG9pbnRzLEEucG9pbnREYXRhLEEuY2VsbHMsQS5jZWxsRGF0YV19dmFyIFZlPWtyO2FzeW5jIGZ1bmN0aW9uIFVyKEEsZSl7bGV0IHQ9InVua25vd24iO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IHI9YCR7dH0ud2FzbWAsaT0oYXdhaXQgTS5nZXQocix7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KSkuZGF0YTtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6aX0pfXZhciBaZT1Vcjt2YXIgWGU9YXN5bmMoKT0+V2ViQXNzZW1ibHkudmFsaWRhdGUobmV3IFVpbnQ4QXJyYXkoWzAsOTcsMTE1LDEwOSwxLDAsMCwwLDEsNSwxLDk2LDAsMSwxMjMsMywyLDEsMCwxMCwxMCwxLDgsMCw2NSwwLDI1MywxNSwyNTMsOTgsMTFdKSk7dmFyIGV0PXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPT0iZnVuY3Rpb24iLCRlPW5ldyBUZXh0RW5jb2RlcixBdD1uZXcgVGV4dERlY29kZXIoInV0Zi04Iik7ZnVuY3Rpb24geChBLGUpe2xldCB0PXtmbGFnczoiciIsZW5jb2Rpbmc6ImJpbmFyeSJ9LHI9QS5mc19vcGVuKGUsdC5mbGFncyksaT1BLmZzX3N0YXQoZSkuc2l6ZSxvPW51bGw7ZXQ/bz1uZXcgU2hhcmVkQXJyYXlCdWZmZXIoaSk6bz1uZXcgQXJyYXlCdWZmZXIoaSk7bGV0IEM9bmV3IFVpbnQ4QXJyYXkobyk7cmV0dXJuIEEuZnNfcmVhZChyLEMsMCxpLDApLEEuZnNfY2xvc2UociksQ31mdW5jdGlvbiB0dChBLGUsdCl7bGV0IHI9bnVsbDtldD9yPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcih0KTpyPW5ldyBBcnJheUJ1ZmZlcih0KTtsZXQgbj1uZXcgVWludDhBcnJheShyKSxpPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixlLHQpO3JldHVybiBuLnNldChpKSxufWZ1bmN0aW9uIFMoQSxlLHQscil7bGV0IG49MDtyZXR1cm4gZSE9PW51bGwmJihuPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2FycmF5X2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQscixlLmJ1ZmZlci5ieXRlTGVuZ3RoXSksQS5IRUFQVTguc2V0KG5ldyBVaW50OEFycmF5KGUuYnVmZmVyKSxuKSksbn1mdW5jdGlvbiBfKEEsZSx0KXtsZXQgcj1KU09OLnN0cmluZ2lmeShlKSxuPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxyLmxlbmd0aF0pO0Eud3JpdGVBc2NpaVRvTWVtb3J5KHIsbiwhMSl9ZnVuY3Rpb24gayhBLGUsdCxyKXtsZXQgbj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxpPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pLG89dHQoQSxuLGkpO3JldHVybiB3KHIsby5idWZmZXIpfWZ1bmN0aW9uICRBKEEsZSl7bGV0IHQ9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2pzb25fYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiXSxbMCxlXSkscj1BLkFzY2lpVG9TdHJpbmcodCk7cmV0dXJuIEpTT04ucGFyc2Uocil9ZnVuY3Rpb24gTnIoQSxlLHQscil7ciE9bnVsbCYmci5sZW5ndGg+MCYmci5mb3JFYWNoKGZ1bmN0aW9uKEksYSl7dmFyIGM7c3dpdGNoKEkudHlwZSl7Y2FzZSBkLlRleHRTdHJlYW06e2xldCBCPSRlLmVuY29kZShJLmRhdGEuZGF0YSksZz1TKEEsQixhLDApLGw9e3NpemU6Qi5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Z31gfTtfKEEsbCxhKTticmVha31jYXNlIGQuSnNvbkNvbXBhdGlibGU6e2xldCBCPSRlLmVuY29kZShKU09OLnN0cmluZ2lmeShJLmRhdGEpKSxnPVMoQSxCLGEsMCksbD17c2l6ZTpCLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtnfWB9O18oQSxsLGEpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBCPUkuZGF0YS5kYXRhLGc9UyhBLEIsYSwwKSxsPXtzaXplOkIuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2d9YH07XyhBLGwsYSk7YnJlYWt9Y2FzZSBkLlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShJLmRhdGEucGF0aCxJLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBkLkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKEkuZGF0YS5wYXRoLEkuZGF0YS5kYXRhKTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBCPUkuZGF0YSxnPVMoQSxCLmRhdGEsYSwwKSxsPVMoQSxCLmRpcmVjdGlvbixhLDEpLGY9dHlwZW9mKChjPUIubWV0YWRhdGEpPT09bnVsbHx8Yz09PXZvaWQgMD92b2lkIDA6Yy5lbnRyaWVzKTwidSI/SlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShCLm1ldGFkYXRhLmVudHJpZXMoKSkpOiJbXSIscD17aW1hZ2VUeXBlOkIuaW1hZ2VUeXBlLG5hbWU6Qi5uYW1lLG9yaWdpbjpCLm9yaWdpbixzcGFjaW5nOkIuc3BhY2luZyxkaXJlY3Rpb246YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsc2l6ZTpCLnNpemUsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2d9YCxtZXRhZGF0YTpmfTtfKEEscCxhKTticmVha31jYXNlIGQuTWVzaDp7bGV0IEI9SS5kYXRhLGc9UyhBLEIucG9pbnRzLGEsMCksbD1TKEEsQi5jZWxscyxhLDEpLGY9UyhBLEIucG9pbnREYXRhLGEsMikscD1TKEEsQi5jZWxsRGF0YSxhLDMpLHk9e21lc2hUeXBlOkIubWVzaFR5cGUsbmFtZTpCLm5hbWUsbnVtYmVyT2ZQb2ludHM6Qi5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtnfWAsbnVtYmVyT2ZDZWxsczpCLm51bWJlck9mQ2VsbHMsY2VsbHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsY2VsbEJ1ZmZlclNpemU6Qi5jZWxsQnVmZmVyU2l6ZSxudW1iZXJPZlBvaW50UGl4ZWxzOkIubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOkIubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7cH1gfTtfKEEseSxhKTticmVha31jYXNlIGQuUG9seURhdGE6e2xldCBCPUkuZGF0YSxnPVMoQSxCLnBvaW50cyxhLDApLGw9UyhBLEIudmVydGljZXMsYSwxKSxmPVMoQSxCLmxpbmVzLGEsMikscD1TKEEsQi5wb2x5Z29ucyxhLDMpLHk9UyhBLEIudHJpYW5nbGVTdHJpcHMsYSw0KSx1PVMoQSxCLnBvaW50RGF0YSxhLDUpLGg9UyhBLEIucG9pbnREYXRhLGEsNiksU0E9e3BvbHlEYXRhVHlwZTpCLnBvbHlEYXRhVHlwZSxuYW1lOkIubmFtZSxudW1iZXJPZlBvaW50czpCLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2d9YCx2ZXJ0aWNlc0J1ZmZlclNpemU6Qi52ZXJ0aWNlc0J1ZmZlclNpemUsdmVydGljZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsbGluZXNCdWZmZXJTaXplOkIubGluZXNCdWZmZXJTaXplLGxpbmVzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLHBvbHlnb25zQnVmZmVyU2l6ZTpCLnBvbHlnb25zQnVmZmVyU2l6ZSxwb2x5Z29uczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3B9YCx0cmlhbmdsZVN0cmlwc0J1ZmZlclNpemU6Qi50cmlhbmdsZVN0cmlwc0J1ZmZlclNpemUsdHJpYW5nbGVTdHJpcHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHt5fWAsbnVtYmVyT2ZQb2ludFBpeGVsczpCLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7dX1gLG51bWJlck9mQ2VsbFBpeGVsczpCLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2h9YH07XyhBLFNBLGEpO2JyZWFrfWNhc2UgUi5UZXh0OntBLmZzX3dyaXRlRmlsZShJLnBhdGgsSS5kYXRhKTticmVha31jYXNlIFIuQmluYXJ5OntBLmZzX3dyaXRlRmlsZShJLnBhdGgsSS5kYXRhKTticmVha31jYXNlIFIuSW1hZ2U6e2xldCBCPUkuZGF0YSxnPXtpbWFnZVR5cGU6Qi5pbWFnZVR5cGUsbmFtZTpCLm5hbWUsb3JpZ2luOkIub3JpZ2luLHNwYWNpbmc6Qi5zcGFjaW5nLGRpcmVjdGlvbjoiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kaXJlY3Rpb24ucmF3IixzaXplOkIuc2l6ZSxkYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2RhdGEucmF3In07aWYoQS5mc19ta2RpcnMoYCR7SS5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShnKSksQi5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UuZGF0YSBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2RhdGEucmF3YCxuZXcgVWludDhBcnJheShCLmRhdGEuYnVmZmVyKSksQS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgLG5ldyBVaW50OEFycmF5KEIuZGlyZWN0aW9uLmJ1ZmZlcikpO2JyZWFrfWNhc2UgUi5NZXNoOntsZXQgQj1JLmRhdGEsZz17bWVzaFR5cGU6Qi5tZXNoVHlwZSxuYW1lOkIubmFtZSxudW1iZXJPZlBvaW50czpCLm51bWJlck9mUG9pbnRzLHBvaW50czoiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9wb2ludHMucmF3IixudW1iZXJPZlBvaW50UGl4ZWxzOkIubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnREYXRhLnJhdyIsbnVtYmVyT2ZDZWxsczpCLm51bWJlck9mQ2VsbHMsY2VsbHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvY2VsbHMucmF3IixudW1iZXJPZkNlbGxQaXhlbHM6Qi5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvY2VsbERhdGEucmF3IixjZWxsQnVmZmVyU2l6ZTpCLmNlbGxCdWZmZXJTaXplfTtpZihBLmZzX21rZGlycyhgJHtJLnBhdGh9L2RhdGFgKSxBLmZzX3dyaXRlRmlsZShgJHtJLnBhdGh9L2luZGV4Lmpzb25gLEpTT04uc3RyaW5naWZ5KGcpKSxnLm51bWJlck9mUG9pbnRzPjApe2lmKEIucG9pbnRzPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke0kucGF0aH0vZGF0YS9wb2ludHMucmF3YCxuZXcgVWludDhBcnJheShCLnBvaW50cy5idWZmZXIpKX1pZihnLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7aWYoQi5wb2ludERhdGE9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLnBvaW50RGF0YSBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL3BvaW50RGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KEIucG9pbnREYXRhLmJ1ZmZlcikpfWlmKGcubnVtYmVyT2ZDZWxscz4wKXtpZihCLmNlbGxzPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5jZWxscyBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2NlbGxzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoQi5jZWxscy5idWZmZXIpKX1pZihnLm51bWJlck9mQ2VsbFBpeGVscz4wKXtpZihCLmNlbGxEYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5jZWxsRGF0YSBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2NlbGxEYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoQi5jZWxsRGF0YS5idWZmZXIpKX1icmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgbj1BLnN0YWNrU2F2ZSgpLGk9MDt0cnl7aT1BLmNhbGxNYWluKGUuc2xpY2UoKSl9Y2F0Y2goSSl7dGhyb3cgdHlwZW9mIEk9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UoSSkpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksSX1maW5hbGx5e0Euc3RhY2tSZXN0b3JlKG4pfWxldCBvPUEuZ2V0TW9kdWxlU3Rkb3V0KCksQz1BLmdldE1vZHVsZVN0ZGVycigpLEU9W107cmV0dXJuIHQhPW51bGwmJnQubGVuZ3RoPjAmJmk9PT0wJiZ0LmZvckVhY2goZnVuY3Rpb24oSSxhKXtsZXQgYz1udWxsO3N3aXRjaChJLnR5cGUpe2Nhc2UgZC5UZXh0U3RyZWFtOntsZXQgZz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxhLDBdKSxsPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGEsMF0pLGY9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLGcsbCk7Yz17ZGF0YTpBdC5kZWNvZGUoZil9O2JyZWFrfWNhc2UgZC5Kc29uQ29tcGF0aWJsZTp7bGV0IGc9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsYSwwXSksbD1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxhLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixnLGwpO2M9SlNPTi5wYXJzZShBdC5kZWNvZGUoZikpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBnPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGEsMF0pLGw9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsYSwwXSk7Yz17ZGF0YTp0dChBLGcsbCl9O2JyZWFrfWNhc2UgZC5UZXh0RmlsZTp7Yz17cGF0aDpJLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUoSS5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIGQuQmluYXJ5RmlsZTp7Yz17cGF0aDpJLmRhdGEucGF0aCxkYXRhOngoQSxJLmRhdGEucGF0aCl9O2JyZWFrfWNhc2UgZC5JbWFnZTp7bGV0IGc9JEEoQSxhKTtnLmRhdGE9ayhBLGEsMCxnLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKSxnLmRpcmVjdGlvbj1rKEEsYSwxLFAuRmxvYXQ2NCksZy5tZXRhZGF0YT1uZXcgTWFwKGcubWV0YWRhdGEpLGM9ZzticmVha31jYXNlIGQuTWVzaDp7bGV0IGc9JEEoQSxhKTtnLm51bWJlck9mUG9pbnRzPjA/Zy5wb2ludHM9ayhBLGEsMCxnLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSk6Zy5wb2ludHM9dyhnLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGcubnVtYmVyT2ZDZWxscz4wP2cuY2VsbHM9ayhBLGEsMSxnLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlKTpnLmNlbGxzPXcoZy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGcubnVtYmVyT2ZQb2ludFBpeGVscz4wP2cucG9pbnREYXRhPWsoQSxhLDIsZy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6Zy5wb2ludERhdGE9dyhnLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksZy5udW1iZXJPZkNlbGxQaXhlbHM+MD9nLmNlbGxEYXRhPWsoQSxhLDMsZy5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlKTpnLmNlbGxEYXRhPXcoZy5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksYz1nO2JyZWFrfWNhc2UgZC5Qb2x5RGF0YTp7bGV0IGc9JEEoQSxhKTtnLm51bWJlck9mUG9pbnRzPjA/Zy5wb2ludHM9ayhBLGEsMCxQLkZsb2F0MzIpOmcucG9pbnRzPW5ldyBGbG9hdDMyQXJyYXksZy52ZXJ0aWNlc0J1ZmZlclNpemU+MD9nLnZlcnRpY2VzPWsoQSxhLDEsRi5VSW50MzIpOmcudmVydGljZXM9bmV3IFVpbnQzMkFycmF5LGcubGluZXNCdWZmZXJTaXplPjA/Zy5saW5lcz1rKEEsYSwyLEYuVUludDMyKTpnLmxpbmVzPW5ldyBVaW50MzJBcnJheSxnLnBvbHlnb25zQnVmZmVyU2l6ZT4wP2cucG9seWdvbnM9ayhBLGEsMyxGLlVJbnQzMik6Zy5wb2x5Z29ucz1uZXcgVWludDMyQXJyYXksZy50cmlhbmdsZVN0cmlwc0J1ZmZlclNpemU+MD9nLnRyaWFuZ2xlU3RyaXBzPWsoQSxhLDQsRi5VSW50MzIpOmcudHJpYW5nbGVTdHJpcHM9bmV3IFVpbnQzMkFycmF5LGcubnVtYmVyT2ZQb2ludFBpeGVscz4wP2cucG9pbnREYXRhPWsoQSxhLDUsZy5wb2x5RGF0YVR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOmcucG9pbnREYXRhPXcoZy5wb2x5RGF0YVR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxnLm51bWJlck9mQ2VsbFBpeGVscz4wP2cuY2VsbERhdGE9ayhBLGEsNixnLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlKTpnLmNlbGxEYXRhPXcoZy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGM9ZzticmVha31jYXNlIFIuVGV4dDp7aWYodHlwZW9mIEkucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO2M9QS5mc19yZWFkRmlsZShJLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pO2JyZWFrfWNhc2UgUi5CaW5hcnk6e2lmKHR5cGVvZiBJLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtjPXgoQSxJLnBhdGgpO2JyZWFrfWNhc2UgUi5JbWFnZTp7aWYodHlwZW9mIEkucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO2xldCBnPUEuZnNfcmVhZEZpbGUoYCR7SS5wYXRofS9pbmRleC5qc29uYCx7ZW5jb2Rpbmc6InV0ZjgifSksbD1KU09OLnBhcnNlKGcpLGY9eChBLGAke0kucGF0aH0vZGF0YS9kYXRhLnJhd2ApO2wuZGF0YT13KGwuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUsZi5idWZmZXIpO2xldCBwPXgoQSxgJHtJLnBhdGh9L2RhdGEvZGlyZWN0aW9uLnJhd2ApO2wuZGlyZWN0aW9uPXcoUC5GbG9hdDY0LHAuYnVmZmVyKSxjPWw7YnJlYWt9Y2FzZSBSLk1lc2g6e2lmKHR5cGVvZiBJLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgZz1BLmZzX3JlYWRGaWxlKGAke0kucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLGw9SlNPTi5wYXJzZShnKTtpZihsLm51bWJlck9mUG9pbnRzPjApe2xldCBmPXgoQSxgJHtJLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2ApO2wucG9pbnRzPXcobC5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsZi5idWZmZXIpfWVsc2UgbC5wb2ludHM9dyhsLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKGwubnVtYmVyT2ZQb2ludFBpeGVscz4wKXtsZXQgZj14KEEsYCR7SS5wYXRofS9kYXRhL3BvaW50RGF0YS5yYXdgKTtsLnBvaW50RGF0YT13KGwubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsZi5idWZmZXIpfWVsc2UgbC5wb2ludERhdGE9dyhsLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYobC5udW1iZXJPZkNlbGxzPjApe2xldCBmPXgoQSxgJHtJLnBhdGh9L2RhdGEvY2VsbHMucmF3YCk7bC5jZWxscz13KGwubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsZi5idWZmZXIpfWVsc2UgbC5jZWxscz13KGwubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihsLm51bWJlck9mQ2VsbFBpeGVscz4wKXtsZXQgZj14KEEsYCR7SS5wYXRofS9kYXRhL2NlbGxEYXRhLnJhd2ApO2wuY2VsbERhdGE9dyhsLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsZi5idWZmZXIpfWVsc2UgbC5jZWxsRGF0YT13KGwubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2M9bDticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBvdXRwdXQgSW50ZXJmYWNlVHlwZSIpfWxldCBCPXt0eXBlOkkudHlwZSxkYXRhOmN9O0UucHVzaChCKX0pLHtyZXR1cm5WYWx1ZTppLHN0ZG91dDpvLHN0ZGVycjpDLG91dHB1dHM6RX19dmFyIHJ0PU5yO3ZhciBBZT1uZXcgTWFwO2FzeW5jIGZ1bmN0aW9uIE9yKEEpe2xldCBlPUEsdD1BO2lmKHR5cGVvZiBBIT0ic3RyaW5nIiYmKGU9bmV3IFVSTChBLmhyZWYpLHQ9ZS5ocmVmKSxBZS5oYXModCkpcmV0dXJuIEFlLmdldCh0KTt7bGV0IHI9YXdhaXQgWmUoQSxILnBpcGVsaW5lc1VybCk7cmV0dXJuIEFlLnNldCh0LHIpLHJ9fWFzeW5jIGZ1bmN0aW9uIEdyKEEsZSx0LHIsbixpKXt2YXIgbyxDO2lmKCFhd2FpdCBYZSgpKXtsZXQgdT0iV2ViQXNzZW1ibHkgU0lNRCBzdXBwb3J0IGlzIHJlcXVpcmVkIC0tIHBsZWFzZSB1cGRhdGUgeW91ciBicm93c2VyLiI7dGhyb3cgYWxlcnQodSksbmV3IEVycm9yKHUpfWlmKEE9PT0hMSl7bGV0IHU9YXdhaXQgT3IoZS50b1N0cmluZygpKTtyZXR1cm4gcnQodSx0LHIsbil9bGV0IEU9QSxJPShvPWk/LnBpcGVsaW5lV29ya2VyVXJsKSE9PW51bGwmJm8hPT12b2lkIDA/bzpudWxsLGE9dHlwZW9mIEkhPSJzdHJpbmciJiZ0eXBlb2YgST8uaHJlZjwidSI/SS5ocmVmOkkse3dvcmtlclByb3h5OmMsd29ya2VyOkJ9PWF3YWl0IFdlKEUsYSk7RT1CO2xldCBnPVtdO24hPW51bGwmJm4ubGVuZ3RoPjAmJm4uZm9yRWFjaChmdW5jdGlvbih1KXtpZih1LnR5cGU9PT1kLkJpbmFyeVN0cmVhbSl7bGV0IGg9dS5kYXRhLmRhdGE7Zy5wdXNoKGgpfWVsc2UgaWYodS50eXBlPT09ZC5CaW5hcnlGaWxlKXtsZXQgaD11LmRhdGEuZGF0YTtnLnB1c2goaCl9ZWxzZSBpZih1LnR5cGU9PT1kLkltYWdlKXtsZXQgaD11LmRhdGE7aWYoaC5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UgZGF0YSBjYW5ub3QgYmUgbnVsbCIpO2cucHVzaCguLi5YQShoKSl9ZWxzZSBpZih1LnR5cGU9PT1SLkJpbmFyeSlnLnB1c2godS5kYXRhKTtlbHNlIGlmKHUudHlwZT09PVIuSW1hZ2Upe2xldCBoPXUuZGF0YTtpZihoLmRhdGE9PT1udWxsKXRocm93IEVycm9yKCJpbWFnZSBkYXRhIGNhbm5vdCBiZSBudWxsIik7Zy5wdXNoKC4uLlhBKGgpKX1lbHNlIGlmKHUudHlwZT09PVIuTWVzaCl7bGV0IGg9dS5kYXRhO2cucHVzaCguLi5WZShoKSl9fSk7bGV0IGw9KEM9aT8ucGlwZWxpbmVCYXNlVXJsKSE9PW51bGwmJkMhPT12b2lkIDA/QzoicGlwZWxpbmVzVXJsIixmPXR5cGVvZiBsIT0ic3RyaW5nIiYmdHlwZW9mIGw/LmhyZWY8InUiP2wuaHJlZjpsLHA9biE9bnVsbD9aQShuLHJlKGcpKTpudWxsLHk9YXdhaXQgYy5ydW5QaXBlbGluZShILGUudG9TdHJpbmcoKSxmLHQscixwKTtyZXR1cm57cmV0dXJuVmFsdWU6eS5yZXR1cm5WYWx1ZSxzdGRvdXQ6eS5zdGRvdXQsc3RkZXJyOnkuc3RkZXJyLG91dHB1dHM6eS5vdXRwdXRzLHdlYldvcmtlcjpFfX12YXIgaUE9R3I7dmFyIG50PXtuYW1lOiJAaXRrLXdhc20vY29tcHJlc3Mtc3RyaW5naWZ5Iix2ZXJzaW9uOiIyLjAuMCIsZGVzY3JpcHRpb246IlpzdGFuZGFyZCBjb21wcmVzc2lvbiBhbmQgZGVjb21wcmVzc2lvbiBhbmQgYmFzZTY0IGVuY29kaW5nIGFuZCBkZWNvZGluZyBpbiBXZWJBc3NlbWJseS4iLHR5cGU6Im1vZHVsZSIsbW9kdWxlOiIuL2Rpc3QvaW5kZXguanMiLHR5cGVzOiIuL2Rpc3QvaW5kZXguZC50cyIsZXhwb3J0czp7Ii4iOnt0eXBlczoiLi9kaXN0L2luZGV4LmQudHMiLGJyb3dzZXI6Ii4vZGlzdC9pbmRleC5qcyIsbm9kZToiLi9kaXN0L2luZGV4LW5vZGUuanMiLGRlZmF1bHQ6Ii4vZGlzdC9pbmRleC5qcyJ9fSxzY3JpcHRzOntzdGFydDoibnBtIHJ1biBjb3B5U2hvZWxhY2VBc3NldHMgJiYgdml0ZSAtYyBidWlsZC92aXRlLmNvbmZpZy5qcyIsdGVzdDoibnBtIHJ1biB0ZXN0Om5vZGUgJiYgbnBtIHJ1biB0ZXN0OmJyb3dzZXIiLCJ0ZXN0Om5vZGUiOiJhdmEgdGVzdC9ub2RlLyouanMiLCJ0ZXN0OmJyb3dzZXIiOiJucG0gcnVuIHRlc3Q6YnJvd3NlcjpjaHJvbWUgJiYgbnBtIHJ1biB0ZXN0OmJyb3dzZXI6ZmlyZWZveCIsInRlc3Q6YnJvd3NlcjpmaXJlZm94Ijoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHN0YXJ0IGh0dHAtZ2V0Oi8vbG9jYWxob3N0OjUxNzMgY3lwcmVzczpydW5GaXJlZm94IiwidGVzdDpicm93c2VyOmNocm9tZSI6InN0YXJ0LXNlcnZlci1hbmQtdGVzdCBzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MTczIGN5cHJlc3M6cnVuQ2hyb21lIiwidGVzdDpicm93c2VyOmRlYnVnIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHN0YXJ0IGh0dHAtZ2V0Oi8vbG9jYWxob3N0OjUxNzMgY3lwcmVzczpvcGVuIixjb3B5U2hvZWxhY2VBc3NldHM6InNoeCBta2RpciAtcCB0ZXN0L2Jyb3dzZXIvZGVtby1hcHAvcHVibGljL3Nob2VsYWNlICYmIHNoeCBjcCAtciBub2RlX21vZHVsZXMvQHNob2VsYWNlLXN0eWxlL3Nob2VsYWNlL2Rpc3QvYXNzZXRzIHRlc3QvYnJvd3Nlci9kZW1vLWFwcC9wdWJsaWMvIiwiY3lwcmVzczpvcGVuIjoibnB4IGN5cHJlc3Mgb3BlbiIsImN5cHJlc3M6cnVuQ2hyb21lIjoibnB4IGN5cHJlc3MgcnVuIC0tYnJvd3NlciBjaHJvbWUiLCJjeXByZXNzOnJ1bkZpcmVmb3giOiJucHggY3lwcmVzcyBydW4gLS1icm93c2VyIGZpcmVmb3giLGJ1aWxkOiJucG0gcnVuIGJ1aWxkOnRzYyAmJiBucG0gcnVuIGJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWQgJiYgbnBtIHJ1biBidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkTWluICYmIG5wbSBydW4gYnVpbGQ6ZGVtbyIsImJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWQiOiJlc2J1aWxkIC0tbG9hZGVyOi53b3JrZXIuanM9ZGF0YXVybCAtLWJ1bmRsZSAtLWZvcm1hdD1lc20gLS1vdXRmaWxlPS4vZGlzdC9idW5kbGUvaW5kZXgtd29ya2VyLWVtYmVkZGVkLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC50cyIsImJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWRNaW4iOiJlc2J1aWxkIC0tbWluaWZ5IC0tbG9hZGVyOi53b3JrZXIuanM9ZGF0YXVybCAtLWJ1bmRsZSAtLWZvcm1hdD1lc20gLS1vdXRmaWxlPS4vZGlzdC9idW5kbGUvaW5kZXgtd29ya2VyLWVtYmVkZGVkLm1pbi5qcyAuL3NyYy9pbmRleC13b3JrZXItZW1iZWRkZWQubWluLnRzIiwiYnVpbGQ6dHNjIjoidHNjIC0tcHJldHR5IiwiYnVpbGQ6ZGVtbyI6Im5wbSBydW4gY29weVNob2VsYWNlQXNzZXRzICYmIHZpdGUgLWMgYnVpbGQvdml0ZS5jb25maWcuanMgYnVpbGQifSxrZXl3b3JkczpbIml0ayIsIndhc20iLCJ3ZWJhc3NlbWJseSJdLGF1dGhvcjoiIixsaWNlbnNlOiJBcGFjaGUtMi4wIixkZXBlbmRlbmNpZXM6eyJpdGstd2FzbSI6Il4xLjAuMC1iLjE1NCJ9LGRldkRlcGVuZGVuY2llczp7IkBzaG9lbGFjZS1zdHlsZS9zaG9lbGFjZSI6Il4yLjUuMiIsIkB0eXBlcy9ub2RlIjoiXjIwLjIuNSIsYXZhOiJeNS4xLjAiLGN5cHJlc3M6Il4xMy4zLjEiLGVzYnVpbGQ6Il4wLjE5LjUiLHNoeDoiXjAuMy40Iiwic3RhcnQtc2VydmVyLWFuZC10ZXN0IjoiXjIuMC4wIix0eXBlc2NyaXB0OiJeNS4wLjQiLHZpdGU6Il40LjQuMTEiLCJ2aXRlLXBsdWdpbi1zdGF0aWMtY29weSI6Il4wLjE3LjAifSxyZXBvc2l0b3J5Ont0eXBlOiJnaXQiLHVybDoiaHR0cHM6Ly9naXRodWIuY29tL0luc2lnaHRTb2Z0d2FyZUNvbnNvcnRpdW0vaXRrLXdhc20ifX07dmFyIGVlLFRyPWBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0BpdGstd2FzbS9jb21wcmVzcy1zdHJpbmdpZnlAJHtudC52ZXJzaW9ufS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gRmEoQSl7ZWU9QX1mdW5jdGlvbiB3QSgpe2lmKHR5cGVvZiBlZTwidSIpcmV0dXJuIGVlO2xldCBBPXplKCk7cmV0dXJuIHR5cGVvZiBBPCJ1Ij9BOlRyfXZhciB0ZSx4cj1udWxsO2Z1bmN0aW9uIGl0KEEpe3RlPUF9ZnVuY3Rpb24gREEoKXtpZih0eXBlb2YgdGU8InUiKXJldHVybiB0ZTtsZXQgQT1fZSgpO3JldHVybiB0eXBlb2YgQTwidSI/QTp4cn1hc3luYyBmdW5jdGlvbiBQcihBLGUsdD17fSl7bGV0IHI9W3t0eXBlOmQuQmluYXJ5U3RyZWFtfV0sbj1be3R5cGU6ZC5CaW5hcnlTdHJlYW0sZGF0YTp7ZGF0YTplfX1dLGk9W10sbz0iMCI7aS5wdXNoKG8pO2xldCBDPSIwIjtpLnB1c2goQyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LnN0cmluZ2lmeTwidSImJnQuc3RyaW5naWZ5JiZpLnB1c2goIi0tc3RyaW5naWZ5IiksdHlwZW9mIHQuY29tcHJlc3Npb25MZXZlbDwidSImJmkucHVzaCgiLS1jb21wcmVzc2lvbi1sZXZlbCIsdC5jb21wcmVzc2lvbkxldmVsLnRvU3RyaW5nKCkpLHR5cGVvZiB0LmRhdGFVcmxQcmVmaXg8InUiJiZpLnB1c2goIi0tZGF0YS11cmwtcHJlZml4Iix0LmRhdGFVcmxQcmVmaXgudG9TdHJpbmcoKSk7bGV0IEU9ImNvbXByZXNzLXN0cmluZ2lmeSIse3dlYldvcmtlcjpJLHJldHVyblZhbHVlOmEsc3RkZXJyOmMsb3V0cHV0czpCfT1hd2FpdCBpQShBLEUsaSxyLG4se3BpcGVsaW5lQmFzZVVybDp3QSgpLHBpcGVsaW5lV29ya2VyVXJsOkRBKCl9KTtpZihhIT09MCYmYyE9PSIiKXRocm93IG5ldyBFcnJvcihjKTtyZXR1cm57d2ViV29ya2VyOkksb3V0cHV0OihCWzBdPy5kYXRhKS5kYXRhfX12YXIgTXI9UHI7YXN5bmMgZnVuY3Rpb24gSnIoQSxlLHQ9e30pe2xldCByPVt7dHlwZTpkLkJpbmFyeVN0cmVhbX1dLG49W3t0eXBlOmQuQmluYXJ5U3RyZWFtLGRhdGE6e2RhdGE6ZX19XSxpPVtdLG89IjAiO2kucHVzaChvKTtsZXQgQz0iMCI7aS5wdXNoKEMpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5wYXJzZVN0cmluZzwidSImJnQucGFyc2VTdHJpbmcmJmkucHVzaCgiLS1wYXJzZS1zdHJpbmciKTtsZXQgRT0icGFyc2Utc3RyaW5nLWRlY29tcHJlc3MiLHt3ZWJXb3JrZXI6SSxyZXR1cm5WYWx1ZTphLHN0ZGVycjpjLG91dHB1dHM6Qn09YXdhaXQgaUEoQSxFLGkscixuLHtwaXBlbGluZUJhc2VVcmw6d0EoKSxwaXBlbGluZVdvcmtlclVybDpEQSgpfSk7aWYoYSE9PTAmJmMhPT0iIil0aHJvdyBuZXcgRXJyb3IoYyk7cmV0dXJue3dlYldvcmtlcjpJLG91dHB1dDooQlswXT8uZGF0YSkuZGF0YX19dmFyIEhyPUpyO3ZhciBvdD0nZGF0YTp0ZXh0L2phdmFzY3JpcHQ7Y2hhcnNldD11dGYtOCx2YXIgY2U9U3ltYm9sKCJDb21saW5rLnByb3h5IiksQ3Q9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IiksQnQ9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLE1BPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksZmU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsUXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmQVtjZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gRUEoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLGx0KEEpfX0sRXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LGxlPW5ldyBNYXAoW1sicHJveHkiLFF0XSxbInRocm93IixFdF1dKTtmdW5jdGlvbiBjdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gRUEoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBJKHIpe2lmKCFyfHwhci5kYXRhKXJldHVybjtpZighY3QodCxyLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gXCcke3Iub3JpZ2lufVwnIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6ZyxwYXRoOm59PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksRT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChxKSxvO3RyeXtsZXQgQj1uLnNsaWNlKDAsLTEpLnJlZHVjZSgoYSxDKT0+YVtDXSxBKSxjPW4ucmVkdWNlKChhLEMpPT5hW0NdLEEpO3N3aXRjaChnKXtjYXNlIkdFVCI6bz1jO2JyZWFrO2Nhc2UiU0VUIjpCW24uc2xpY2UoLTEpWzBdXT1xKHIuZGF0YS52YWx1ZSksbz0hMDticmVhaztjYXNlIkFQUExZIjpvPWMuYXBwbHkoQixFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBhPW5ldyBjKC4uLkUpO289bXQoYSl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTphLHBvcnQyOkN9PW5ldyBNZXNzYWdlQ2hhbm5lbDtFQShBLEMpLG89SEEoYSxbYV0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6bz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKEIpe289e3ZhbHVlOkIsW3NBXTowfX1Qcm9taXNlLnJlc29sdmUobykuY2F0Y2goQj0+KHt2YWx1ZTpCLFtzQV06MH0pKS50aGVuKEI9PntsZXRbYyxhXT1RQShCKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLGEpLGc9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLHVlKGUpLE1BIGluIEEmJnR5cGVvZiBBW01BXT09ImZ1bmN0aW9uIiYmQVtNQV0oKSl9KS5jYXRjaChCPT57bGV0W2MsYV09UUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtzQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LGMpLHtpZDppfSksYSl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBmdChBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiB1ZShBKXtmdChBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGx0KEEsZSl7cmV0dXJuIGJBKEEsW10sZSl9ZnVuY3Rpb24gYUEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIGhlKEEpe3JldHVybiB4KEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e3VlKEEpfSl9dmFyIENBPW5ldyBXZWFrTWFwLEJBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPShDQS5nZXQoQSl8fDApLTE7Q0Euc2V0KEEsZSksZT09PTAmJmhlKEEpfSk7ZnVuY3Rpb24gdXQoQSxlKXtsZXQgdD0oQ0EuZ2V0KGUpfHwwKSsxO0NBLnNldChlLHQpLEJBJiZCQS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gaHQoQSl7QkEmJkJBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gYkEoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgST0hMSxyPW5ldyBQcm94eSh0LHtnZXQoaSxnKXtpZihhQShJKSxnPT09QnQpcmV0dXJuKCk9PntodChyKSxoZShBKSxJPSEwfTtpZihnPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9PnJ9O2xldCBuPXgoQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKEU9PkUudG9TdHJpbmcoKSl9KS50aGVuKHEpO3JldHVybiBuLnRoZW4uYmluZChuKX1yZXR1cm4gYkEoQSxbLi4uZSxnXSl9LHNldChpLGcsbil7YUEoSSk7bGV0W0Usb109UUEobik7cmV0dXJuIHgoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGddLm1hcChCPT5CLnRvU3RyaW5nKCkpLHZhbHVlOkV9LG8pLnRoZW4ocSl9LGFwcGx5KGksZyxuKXthQShJKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1DdClyZXR1cm4geChBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKHEpO2lmKEU9PT0iYmluZCIpcmV0dXJuIGJBKEEsZS5zbGljZSgwLC0xKSk7bGV0W28sQl09RWUobik7cmV0dXJuIHgoQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoYz0+Yy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6b30sQikudGhlbihxKX0sY29uc3RydWN0KGksZyl7YUEoSSk7bGV0W24sRV09RWUoZyk7cmV0dXJuIHgoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKG89Pm8udG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Om59LEUpLnRoZW4ocSl9fSk7cmV0dXJuIHV0KHIsQSkscn1mdW5jdGlvbiBkdChBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBFZShBKXtsZXQgZT1BLm1hcChRQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGR0KGUubWFwKHQ9PnRbMV0pKV19dmFyIGRlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIEhBKEEsZSl7cmV0dXJuIGRlLnNldChBLGUpLEF9ZnVuY3Rpb24gbXQoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W2NlXTohMH0pfWZ1bmN0aW9uIFFBKEEpe2ZvcihsZXRbZSx0XW9mIGxlKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZGUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gcShBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBsZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIHgoQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShJPT57bGV0IHI9RHQoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkoZyl7IWcuZGF0YXx8IWcuZGF0YS5pZHx8Zy5kYXRhLmlkIT09cnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSksSShnLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOnJ9LGUpLHQpfSl9ZnVuY3Rpb24gRHQoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIFgoQSxlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShlLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzp5dH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6VEF9PU9iamVjdCxmQT0oQT0+ZT0+e2xldCB0PXl0LmNhbGwoZSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxVPUE9PihBPUEudG9Mb3dlckNhc2UoKSxlPT5mQShlKT09PUEpLGxBPUE9PmU9PnR5cGVvZiBlPT09QSx7aXNBcnJheTpQfT1BcnJheSx2PWxBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiB3dChBKXtyZXR1cm4gQSE9PW51bGwmJiF2KEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIXYoQS5jb25zdHJ1Y3RvcikmJlIoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIHdlPVUoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gcHQoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZ3ZShBLmJ1ZmZlciksZX12YXIgRnQ9bEEoInN0cmluZyIpLFI9bEEoImZ1bmN0aW9uIikscGU9bEEoIm51bWJlciIpLHVBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsU3Q9QT0+QT09PSEwfHxBPT09ITEsY0E9QT0+e2lmKGZBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9VEEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sTnQ9VSgiRGF0ZSIpLFJ0PVUoIkZpbGUiKSxHdD1VKCJCbG9iIiksVXQ9VSgiRmlsZUxpc3QiKSxrdD1BPT51QShBKSYmUihBLnBpcGUpLEx0PUE9PntsZXQgZTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxSKEEuYXBwZW5kKSYmKChlPWZBKEEpKT09PSJmb3JtZGF0YSJ8fGU9PT0ib2JqZWN0IiYmUihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxPdD1VKCJVUkxTZWFyY2hQYXJhbXMiKSxKdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gJChBLGUse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBJLHI7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLFAoQSkpZm9yKEk9MCxyPUEubGVuZ3RoO0k8cjtJKyspZS5jYWxsKG51bGwsQVtJXSxJLEEpO2Vsc2V7bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxnPWkubGVuZ3RoLG47Zm9yKEk9MDtJPGc7SSsrKW49aVtJXSxlLmNhbGwobnVsbCxBW25dLG4sQSl9fWZ1bmN0aW9uIEZlKEEsZSl7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgU2U9KCgpPT50eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsKSgpLE5lPUE9PiF2KEEpJiZBIT09U2U7ZnVuY3Rpb24gcUEoKXtsZXR7Y2FzZWxlc3M6QX09TmUodGhpcykmJnRoaXN8fHt9LGU9e30sdD0oSSxyKT0+e2xldCBpPUEmJkZlKGUscil8fHI7Y0EoZVtpXSkmJmNBKEkpP2VbaV09cUEoZVtpXSxJKTpjQShJKT9lW2ldPXFBKHt9LEkpOlAoSSk/ZVtpXT1JLnNsaWNlKCk6ZVtpXT1JfTtmb3IobGV0IEk9MCxyPWFyZ3VtZW50cy5sZW5ndGg7STxyO0krKylhcmd1bWVudHNbSV0mJiQoYXJndW1lbnRzW0ldLHQpO3JldHVybiBlfXZhciBNdD0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4oJChlLChyLGkpPT57dCYmUihyKT9BW2ldPVgocix0KTpBW2ldPXJ9LHthbGxPd25LZXlzOkl9KSxBKSxidD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLEh0PShBLGUsdCxJKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZS5wcm90b3R5cGUsSSksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTplLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LFl0PShBLGUsdCxJKT0+e2xldCByLGksZyxuPXt9O2lmKGU9ZXx8e30sQT09bnVsbClyZXR1cm4gZTtkb3tmb3Iocj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxpPXIubGVuZ3RoO2ktLSA+MDspZz1yW2ldLCghSXx8SShnLEEsZSkpJiYhbltnXSYmKGVbZ109QVtnXSxuW2ddPSEwKTtBPXQhPT0hMSYmVEEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsZSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIGV9LHF0PShBLGUsdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1lLmxlbmd0aDtsZXQgST1BLmluZGV4T2YoZSx0KTtyZXR1cm4gSSE9PS0xJiZJPT09dH0sVHQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKFAoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIXBlKGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxLdD0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmVEEoVWludDhBcnJheSkpLHh0PShBLGUpPT57bGV0IEk9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxyO2Zvcig7KHI9SS5uZXh0KCkpJiYhci5kb25lOyl7bGV0IGk9ci52YWx1ZTtlLmNhbGwoQSxpWzBdLGlbMV0pfX0sUHQ9KEEsZSk9PntsZXQgdCxJPVtdO2Zvcig7KHQ9QS5leGVjKGUpKSE9PW51bGw7KUkucHVzaCh0KTtyZXR1cm4gSX0sV3Q9VSgiSFRNTEZvcm1FbGVtZW50IiksanQ9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24odCxJLHIpe3JldHVybiBJLnRvVXBwZXJDYXNlKCkrcn0pLERlPSgoe2hhc093blByb3BlcnR5OkF9KT0+KGUsdCk9PkEuY2FsbChlLHQpKShPYmplY3QucHJvdG90eXBlKSxadD1VKCJSZWdFeHAiKSxSZT0oQSxlKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLEk9e307JCh0LChyLGkpPT57ZShyLGksQSkhPT0hMSYmKElbaV09cil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLEkpfSxfdD1BPT57UmUoQSwoZSx0KT0+e2lmKFIoQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCBJPUFbdF07aWYoUihJKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kIFwnIit0KyJcJyIpfSl9fSl9LFZ0PShBLGUpPT57bGV0IHQ9e30sST1yPT57ci5mb3JFYWNoKGk9Pnt0W2ldPSEwfSl9O3JldHVybiBQKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LHp0PSgpPT57fSxYdD0oQSxlKT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6ZSksWUE9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iix5ZT0iMDEyMzQ1Njc4OSIsR2U9e0RJR0lUOnllLEFMUEhBOllBLEFMUEhBX0RJR0lUOllBK1lBLnRvVXBwZXJDYXNlKCkreWV9LHZ0PShBPTE2LGU9R2UuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpJfT1lO2Zvcig7QS0tOyl0Kz1lW01hdGgucmFuZG9tKCkqSXwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gJHQoQSl7cmV0dXJuISEoQSYmUihBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIEFJPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZih1QShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1QKEkpP1tdOnt9O3JldHVybiAkKEksKGcsbik9PntsZXQgRT10KGcscisxKTshdihFKSYmKGlbbl09RSl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sZUk9VSgiQXN5bmNGdW5jdGlvbiIpLHRJPUE9PkEmJih1QShBKXx8UihBKSkmJlIoQS50aGVuKSYmUihBLmNhdGNoKSxzPXtpc0FycmF5OlAsaXNBcnJheUJ1ZmZlcjp3ZSxpc0J1ZmZlcjp3dCxpc0Zvcm1EYXRhOkx0LGlzQXJyYXlCdWZmZXJWaWV3OnB0LGlzU3RyaW5nOkZ0LGlzTnVtYmVyOnBlLGlzQm9vbGVhbjpTdCxpc09iamVjdDp1QSxpc1BsYWluT2JqZWN0OmNBLGlzVW5kZWZpbmVkOnYsaXNEYXRlOk50LGlzRmlsZTpSdCxpc0Jsb2I6R3QsaXNSZWdFeHA6WnQsaXNGdW5jdGlvbjpSLGlzU3RyZWFtOmt0LGlzVVJMU2VhcmNoUGFyYW1zOk90LGlzVHlwZWRBcnJheTpLdCxpc0ZpbGVMaXN0OlV0LGZvckVhY2g6JCxtZXJnZTpxQSxleHRlbmQ6TXQsdHJpbTpKdCxzdHJpcEJPTTpidCxpbmhlcml0czpIdCx0b0ZsYXRPYmplY3Q6WXQsa2luZE9mOmZBLGtpbmRPZlRlc3Q6VSxlbmRzV2l0aDpxdCx0b0FycmF5OlR0LGZvckVhY2hFbnRyeTp4dCxtYXRjaEFsbDpQdCxpc0hUTUxGb3JtOld0LGhhc093blByb3BlcnR5OkRlLGhhc093blByb3A6RGUscmVkdWNlRGVzY3JpcHRvcnM6UmUsZnJlZXplTWV0aG9kczpfdCx0b09iamVjdFNldDpWdCx0b0NhbWVsQ2FzZTpqdCxub29wOnp0LHRvRmluaXRlTnVtYmVyOlh0LGZpbmRLZXk6RmUsZ2xvYmFsOlNlLGlzQ29udGV4dERlZmluZWQ6TmUsQUxQSEFCRVQ6R2UsZ2VuZXJhdGVTdHJpbmc6dnQsaXNTcGVjQ29tcGxpYW50Rm9ybTokdCx0b0pTT05PYmplY3Q6QUksaXNBc3luY0ZuOmVJLGlzVGhlbmFibGU6dEl9O2Z1bmN0aW9uIFcoQSxlLHQsSSxyKXtFcnJvci5jYWxsKHRoaXMpLEVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsdGhpcy5jb25zdHJ1Y3Rvcik6dGhpcy5zdGFjaz1uZXcgRXJyb3IoKS5zdGFjayx0aGlzLm1lc3NhZ2U9QSx0aGlzLm5hbWU9IkF4aW9zRXJyb3IiLGUmJih0aGlzLmNvZGU9ZSksdCYmKHRoaXMuY29uZmlnPXQpLEkmJih0aGlzLnJlcXVlc3Q9SSksciYmKHRoaXMucmVzcG9uc2U9cil9cy5pbmhlcml0cyhXLEVycm9yLHt0b0pTT046ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6cy50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX19KTt2YXIgVWU9Vy5wcm90b3R5cGUsa2U9e307WyJFUlJfQkFEX09QVElPTl9WQUxVRSIsIkVSUl9CQURfT1BUSU9OIiwiRUNPTk5BQk9SVEVEIiwiRVRJTUVET1VUIiwiRVJSX05FVFdPUksiLCJFUlJfRlJfVE9PX01BTllfUkVESVJFQ1RTIiwiRVJSX0RFUFJFQ0FURUQiLCJFUlJfQkFEX1JFU1BPTlNFIiwiRVJSX0JBRF9SRVFVRVNUIiwiRVJSX0NBTkNFTEVEIiwiRVJSX05PVF9TVVBQT1JUIiwiRVJSX0lOVkFMSURfVVJMIl0uZm9yRWFjaChBPT57a2VbQV09e3ZhbHVlOkF9fSk7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVyxrZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KFVlLCJpc0F4aW9zRXJyb3IiLHt2YWx1ZTohMH0pO1cuZnJvbT0oQSxlLHQsSSxyLGkpPT57bGV0IGc9T2JqZWN0LmNyZWF0ZShVZSk7cmV0dXJuIHMudG9GbGF0T2JqZWN0KEEsZyxmdW5jdGlvbihFKXtyZXR1cm4gRSE9PUVycm9yLnByb3RvdHlwZX0sbj0+biE9PSJpc0F4aW9zRXJyb3IiKSxXLmNhbGwoZyxBLm1lc3NhZ2UsZSx0LEksciksZy5jYXVzZT1BLGcubmFtZT1BLm5hbWUsaSYmT2JqZWN0LmFzc2lnbihnLGkpLGd9O3ZhciBsPVc7dmFyIGhBPW51bGw7ZnVuY3Rpb24gS0EoQSl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChBKXx8cy5pc0FycmF5KEEpfWZ1bmN0aW9uIE9lKEEpe3JldHVybiBzLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIExlKEEsZSx0KXtyZXR1cm4gQT9BLmNvbmNhdChlKS5tYXAoZnVuY3Rpb24ocixpKXtyZXR1cm4gcj1PZShyKSwhdCYmaT8iWyIrcisiXSI6cn0pLmpvaW4odD8iLiI6IiIpOmV9ZnVuY3Rpb24gSUkoQSl7cmV0dXJuIHMuaXNBcnJheShBKSYmIUEuc29tZShLQSl9dmFyIHJJPXMudG9GbGF0T2JqZWN0KHMse30sbnVsbCxmdW5jdGlvbihlKXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QoZSl9KTtmdW5jdGlvbiBpSShBLGUsdCl7aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7ZT1lfHxuZXcoaEF8fEZvcm1EYXRhKSx0PXMudG9GbGF0T2JqZWN0KHQse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLG0pe3JldHVybiFzLmlzVW5kZWZpbmVkKG1bZl0pfSk7bGV0IEk9dC5tZXRhVG9rZW5zLHI9dC52aXNpdG9yfHxCLGk9dC5kb3RzLGc9dC5pbmRleGVzLEU9KHQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmcy5pc1NwZWNDb21wbGlhbnRGb3JtKGUpO2lmKCFzLmlzRnVuY3Rpb24ocikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBvKFEpe2lmKFE9PT1udWxsKXJldHVybiIiO2lmKHMuaXNEYXRlKFEpKXJldHVybiBRLnRvSVNPU3RyaW5nKCk7aWYoIUUmJnMuaXNCbG9iKFEpKXRocm93IG5ldyBsKCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBzLmlzQXJyYXlCdWZmZXIoUSl8fHMuaXNUeXBlZEFycmF5KFEpP0UmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtRXSk6QnVmZmVyLmZyb20oUSk6UX1mdW5jdGlvbiBCKFEsZixtKXtsZXQgdz1RO2lmKFEmJiFtJiZ0eXBlb2YgUT09Im9iamVjdCIpe2lmKHMuZW5kc1dpdGgoZiwie30iKSlmPUk/ZjpmLnNsaWNlKDAsLTIpLFE9SlNPTi5zdHJpbmdpZnkoUSk7ZWxzZSBpZihzLmlzQXJyYXkoUSkmJklJKFEpfHwocy5pc0ZpbGVMaXN0KFEpfHxzLmVuZHNXaXRoKGYsIltdIikpJiYodz1zLnRvQXJyYXkoUSkpKXJldHVybiBmPU9lKGYpLHcuZm9yRWFjaChmdW5jdGlvbihLLEpBKXshKHMuaXNVbmRlZmluZWQoSyl8fEs9PT1udWxsKSYmZS5hcHBlbmQoZz09PSEwP0xlKFtmXSxKQSxpKTpnPT09bnVsbD9mOmYrIltdIixvKEspKX0pLCExfXJldHVybiBLQShRKT8hMDooZS5hcHBlbmQoTGUobSxmLGkpLG8oUSkpLCExKX1sZXQgYz1bXSxhPU9iamVjdC5hc3NpZ24ockkse2RlZmF1bHRWaXNpdG9yOkIsY29udmVydFZhbHVlOm8saXNWaXNpdGFibGU6S0F9KTtmdW5jdGlvbiBDKFEsZil7aWYoIXMuaXNVbmRlZmluZWQoUSkpe2lmKGMuaW5kZXhPZihRKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Yy5wdXNoKFEpLHMuZm9yRWFjaChRLGZ1bmN0aW9uKHcsTyl7KCEocy5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZyLmNhbGwoZSx3LHMuaXNTdHJpbmcoTyk/Ty50cmltKCk6TyxmLGEpKT09PSEwJiZDKHcsZj9mLmNvbmNhdChPKTpbT10pfSksYy5wb3AoKX19aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBDKEEpLGV9dmFyIEo9aUk7ZnVuY3Rpb24gSmUoQSl7bGV0IGU9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIiwiJTI1MDAiOiJcXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shXCcoKX5dfCUyNTIwfCUyNTAwL2csZnVuY3Rpb24oSSl7cmV0dXJuIGVbSV19KX1mdW5jdGlvbiBNZShBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJkooQSx0aGlzLGUpfXZhciBiZT1NZS5wcm90b3R5cGU7YmUuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O2JlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24oSSl7cmV0dXJuIGUuY2FsbCh0aGlzLEksSmUpfTpKZTtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiB0KHJbMF0pKyI9Iit0KHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgZEE9TWU7ZnVuY3Rpb24gZ0koQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lMjUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNTI0L2csIiQiKS5yZXBsYWNlKC8lMjUyQy9naSwiLCIpLnJlcGxhY2UoLyUyNTIwL2csIisiKS5yZXBsYWNlKC8lMjU1Qi9naSwiWyIpLnJlcGxhY2UoLyUyNTVEL2dpLCJdIil9ZnVuY3Rpb24gQUEoQSxlLHQpe2lmKCFlKXJldHVybiBBO2xldCBJPXQmJnQuZW5jb2RlfHxnSSxyPXQmJnQuc2VyaWFsaXplLGk7aWYocj9pPXIoZSx0KTppPXMuaXNVUkxTZWFyY2hQYXJhbXMoZSk/ZS50b1N0cmluZygpOm5ldyBkQShlLHQpLnRvU3RyaW5nKEkpLGkpe2xldCBnPUEuaW5kZXhPZigiJTIzIik7ZyE9PS0xJiYoQT1BLnNsaWNlKDAsZykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIHhBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LEkpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6ST9JLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ST9JLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihJKXtJIT09bnVsbCYmZShJKX0pfX0sUEE9eEE7dmFyIG1BPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgSGU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOmRBO3ZhciBZZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIHFlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIG9JPSgoKT0+e2xldCBBO3JldHVybiB0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmKChBPW5hdmlnYXRvci5wcm9kdWN0KT09PSJSZWFjdE5hdGl2ZSJ8fEE9PT0iTmF0aXZlU2NyaXB0Inx8QT09PSJOUyIpPyExOnR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUifSkoKSxuST0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKSxEPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkhlLEZvcm1EYXRhOlllLEJsb2I6cWV9LGlzU3RhbmRhcmRCcm93c2VyRW52Om9JLGlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52Om5JLHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTtmdW5jdGlvbiBXQShBLGUpe3JldHVybiBKKEEsbmV3IEQuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LEkscixpKXtyZXR1cm4gRC5pc05vZGUmJnMuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKEksdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LGUpKX1mdW5jdGlvbiBhSShBKXtyZXR1cm4gcy5tYXRjaEFsbCgvXFx3K3xcXFsoXFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIHNJKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSksSSxyPXQubGVuZ3RoLGk7Zm9yKEk9MDtJPHI7SSsrKWk9dFtJXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gQ0koQSl7ZnVuY3Rpb24gZSh0LEkscixpKXtsZXQgZz10W2krK10sbj1OdW1iZXIuaXNGaW5pdGUoK2cpLEU9aT49dC5sZW5ndGg7cmV0dXJuIGc9IWcmJnMuaXNBcnJheShyKT9yLmxlbmd0aDpnLEU/KHMuaGFzT3duUHJvcChyLGcpP3JbZ109W3JbZ10sSV06cltnXT1JLCFuKTooKCFyW2ddfHwhcy5pc09iamVjdChyW2ddKSkmJihyW2ddPVtdKSxlKHQsSSxyW2ddLGkpJiZzLmlzQXJyYXkocltnXSkmJihyW2ddPXNJKHJbZ10pKSwhbil9aWYocy5pc0Zvcm1EYXRhKEEpJiZzLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIHMuZm9yRWFjaEVudHJ5KEEsKEkscik9PntlKGFJKEkpLHIsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIERBPUNJO3ZhciBCST17IkNvbnRlbnQtVHlwZSI6dm9pZCAwfTtmdW5jdGlvbiBRSShBLGUsdCl7aWYocy5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKGV8fEpTT04ucGFyc2UpKEEpLHMudHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgeUE9e3RyYW5zaXRpb25hbDptQSxhZGFwdGVyOlsieGhyIiwiaHR0cCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7bGV0IEk9dC5nZXRDb250ZW50VHlwZSgpfHwiIixyPUkuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLGk9cy5pc09iamVjdChlKTtpZihpJiZzLmlzSFRNTEZvcm0oZSkmJihlPW5ldyBGb3JtRGF0YShlKSkscy5pc0Zvcm1EYXRhKGUpKXJldHVybiByJiZyP0pTT04uc3RyaW5naWZ5KERBKGUpKTplO2lmKHMuaXNBcnJheUJ1ZmZlcihlKXx8cy5pc0J1ZmZlcihlKXx8cy5pc1N0cmVhbShlKXx8cy5pc0ZpbGUoZSl8fHMuaXNCbG9iKGUpKXJldHVybiBlO2lmKHMuaXNBcnJheUJ1ZmZlclZpZXcoZSkpcmV0dXJuIGUuYnVmZmVyO2lmKHMuaXNVUkxTZWFyY2hQYXJhbXMoZSkpcmV0dXJuIHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksZS50b1N0cmluZygpO2xldCBuO2lmKGkpe2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIFdBKGUsdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigobj1zLmlzRmlsZUxpc3QoZSkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEU9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBKKG4/eyJmaWxlc1tdIjplfTplLEUmJm5ldyBFLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gaXx8cj8odC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLFFJKGUpKTplfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKGUpe2xldCB0PXRoaXMudHJhbnNpdGlvbmFsfHx5QS50cmFuc2l0aW9uYWwsST10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLHI9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYoZSYmcy5pc1N0cmluZyhlKSYmKEkmJiF0aGlzLnJlc3BvbnNlVHlwZXx8cikpe2xldCBnPSEodCYmdC5zaWxlbnRKU09OUGFyc2luZykmJnI7dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpfWNhdGNoKG4pe2lmKGcpdGhyb3cgbi5uYW1lPT09IlN5bnRheEVycm9yIj9sLmZyb20obixsLkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOm59fXJldHVybiBlfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpELmNsYXNzZXMuRm9ybURhdGEsQmxvYjpELmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTIwMCYmZTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoifX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiXSxmdW5jdGlvbihlKXt5QS5oZWFkZXJzW2VdPXt9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7eUEuaGVhZGVyc1tlXT1zLm1lcmdlKEJJKX0pO3ZhciBqPXlBO3ZhciBFST1zLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLFRlPUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgJTBBYCkuZm9yRWFjaChmdW5jdGlvbihnKXtyPWcuaW5kZXhPZigiOiIpLHQ9Zy5zdWJzdHJpbmcoMCxyKS50cmltKCkudG9Mb3dlckNhc2UoKSxJPWcuc3Vic3RyaW5nKHIrMSkudHJpbSgpLCEoIXR8fGVbdF0mJkVJW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2goSSk6ZVt0XT1bSV06ZVt0XT1lW3RdP2VbdF0rIiwgIitJOkkpfSksZX07dmFyIEtlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiB3QShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6cy5pc0FycmF5KEEpP0EubWFwKHdBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gY0koQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15cXHMsOz1dKylcXHMqKD86PVxccyooW14sO10rKSk/L2csSTtmb3IoO0k9dC5leGVjKEEpOyllW0lbMV1dPUlbMl07cmV0dXJuIGV9dmFyIGZJPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhJTIzJCUmXCcqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIGpBKEEsZSx0LEkscil7aWYocy5pc0Z1bmN0aW9uKEkpKXJldHVybiBJLmNhbGwodGhpcyxlLHQpO2lmKHImJihlPXQpLCEhcy5pc1N0cmluZyhlKSl7aWYocy5pc1N0cmluZyhJKSlyZXR1cm4gZS5pbmRleE9mKEkpIT09LTE7aWYocy5pc1JlZ0V4cChJKSlyZXR1cm4gSS50ZXN0KGUpfX1mdW5jdGlvbiBsSShBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxcZF0pKFxcdyopL2csKGUsdCxJKT0+dC50b1VwcGVyQ2FzZSgpK0kpfWZ1bmN0aW9uIHVJKEEsZSl7bGV0IHQ9cy50b0NhbWVsQ2FzZSgiICIrZSk7WyJnZXQiLCJzZXQiLCJoYXMiXS5mb3JFYWNoKEk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxJK3Qse3ZhbHVlOmZ1bmN0aW9uKHIsaSxnKXtyZXR1cm4gdGhpc1tJXS5jYWxsKHRoaXMsZSxyLGksZyl9LGNvbmZpZ3VyYWJsZTohMH0pfSl9dmFyIFo9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkobixFLG8pe2xldCBCPWVBKEUpO2lmKCFCKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgYz1zLmZpbmRLZXkocixCKTsoIWN8fHJbY109PT12b2lkIDB8fG89PT0hMHx8bz09PXZvaWQgMCYmcltjXSE9PSExKSYmKHJbY3x8RV09d0EobikpfWxldCBnPShuLEUpPT5zLmZvckVhY2gobiwobyxCKT0+aShvLEIsRSkpO3JldHVybiBzLmlzUGxhaW5PYmplY3QoZSl8fGUgaW5zdGFuY2VvZiB0aGlzLmNvbnN0cnVjdG9yP2coZSx0KTpzLmlzU3RyaW5nKGUpJiYoZT1lLnRyaW0oKSkmJiFmSShlKT9nKFRlKGUpLHQpOmUhPW51bGwmJmkodCxlLEkpLHRoaXN9Z2V0KGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gY0kocik7aWYocy5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKHMuaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGpBKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkoZyl7aWYoZz1lQShnKSxnKXtsZXQgbj1zLmZpbmRLZXkoSSxnKTtuJiYoIXR8fGpBKEksSVtuXSxuLHQpKSYmKGRlbGV0ZSBJW25dLHI9ITApfX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGpBKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IGc9cy5maW5kS2V5KEksaSk7aWYoZyl7dFtnXT13QShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IG49ZT9sSShpKTpTdHJpbmcoaSkudHJpbSgpO24hPT1pJiZkZWxldGUgdFtpXSx0W25dPXdBKHIpLElbbl09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gcy5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJnMuaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYCUwQWApfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0aGlzP2U6bmV3IHRoaXMoZSl9c3RhdGljIGNvbmNhdChlLC4uLnQpe2xldCBJPW5ldyB0aGlzKGUpO3JldHVybiB0LmZvckVhY2gocj0+SS5zZXQocikpLEl9c3RhdGljIGFjY2Vzc29yKGUpe2xldCBJPSh0aGlzW0tlXT10aGlzW0tlXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLHI9dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gaShnKXtsZXQgbj1lQShnKTtJW25dfHwodUkocixnKSxJW25dPSEwKX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHRoaXN9fTtaLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtzLmZyZWV6ZU1ldGhvZHMoWi5wcm90b3R5cGUpO3MuZnJlZXplTWV0aG9kcyhaKTt2YXIgcD1aO2Z1bmN0aW9uIHRBKEEsZSl7bGV0IHQ9dGhpc3x8aixJPWV8fHQscj1wLmZyb20oSS5oZWFkZXJzKSxpPUkuZGF0YTtyZXR1cm4gcy5mb3JFYWNoKEEsZnVuY3Rpb24obil7aT1uLmNhbGwodCxpLHIubm9ybWFsaXplKCksZT9lLnN0YXR1czp2b2lkIDApfSksci5ub3JtYWxpemUoKSxpfWZ1bmN0aW9uIElBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9ZnVuY3Rpb24geGUoQSxlLHQpe2wuY2FsbCh0aGlzLEE/PyJjYW5jZWxlZCIsbC5FUlJfQ0FOQ0VMRUQsZSx0KSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IifXMuaW5oZXJpdHMoeGUsbCx7X19DQU5DRUxfXzohMH0pO3ZhciBNPXhlO2Z1bmN0aW9uIFpBKEEsZSx0KXtsZXQgST10LmNvbmZpZy52YWxpZGF0ZVN0YXR1czshdC5zdGF0dXN8fCFJfHxJKHQuc3RhdHVzKT9BKHQpOmUobmV3IGwoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIit0LnN0YXR1cyxbbC5FUlJfQkFEX1JFUVVFU1QsbC5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKHQuc3RhdHVzLzEwMCktNF0sdC5jb25maWcsdC5yZXF1ZXN0LHQpKX12YXIgUGU9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LEkscixpLGcsbil7bGV0IEU9W107RS5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChJKSkscy5pc051bWJlcihyKSYmRS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUocikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmRS5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhnKSYmRS5wdXNoKCJkb21haW49IitnKSxuPT09ITAmJkUucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPUUuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgST1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xcXFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIEk/ZGVjb2RlVVJJQ29tcG9uZW50KElbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBfQShBKXtyZXR1cm4vXihbYS16XVthLXpcXGQrXFwtLl0qOik/XFwvXFwvL2kudGVzdChBKX1mdW5jdGlvbiBWQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXFwvKyQvLCIiKSsiLyIrZS5yZXBsYWNlKC9eXFwvKy8sIiIpOkF9ZnVuY3Rpb24gckEoQSxlKXtyZXR1cm4gQSYmIV9BKGUpP1ZBKEEsZSk6ZX12YXIgV2U9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBlPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIiksSTtmdW5jdGlvbiByKGkpe2xldCBnPWk7cmV0dXJuIGUmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsZyksZz10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixnKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiUyMy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIEk9cih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oZyl7bGV0IG49cy5pc1N0cmluZyhnKT9yKGcpOmc7cmV0dXJuIG4ucHJvdG9jb2w9PT1JLnByb3RvY29sJiZuLmhvc3Q9PT1JLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIHpBKEEpe2xldCBlPS9eKFstK1xcd117MSwyNX0pKDo/XFwvXFwvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBoSShBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsZztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKEUpe2xldCBvPURhdGUubm93KCksQj1JW2ldO2d8fChnPW8pLHRbcl09RSxJW3JdPW87bGV0IGM9aSxhPTA7Zm9yKDtjIT09cjspYSs9dFtjKytdLGM9YyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksby1nPGUpcmV0dXJuO2xldCBDPUImJm8tQjtyZXR1cm4gQz9NYXRoLnJvdW5kKGEqMWUzL0MpOnZvaWQgMH19dmFyIGplPWhJO2Z1bmN0aW9uIFplKEEsZSl7bGV0IHQ9MCxJPWplKDUwLDI1MCk7cmV0dXJuIHI9PntsZXQgaT1yLmxvYWRlZCxnPXIubGVuZ3RoQ29tcHV0YWJsZT9yLnRvdGFsOnZvaWQgMCxuPWktdCxFPUkobiksbz1pPD1nO3Q9aTtsZXQgQj17bG9hZGVkOmksdG90YWw6Zyxwcm9ncmVzczpnP2kvZzp2b2lkIDAsYnl0ZXM6bixyYXRlOkV8fHZvaWQgMCxlc3RpbWF0ZWQ6RSYmZyYmbz8oZy1pKS9FOnZvaWQgMCxldmVudDpyfTtCW2U/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsQShCKX19dmFyIGRJPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsX2U9ZEkmJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LEkpe2xldCByPUEuZGF0YSxpPXAuZnJvbShBLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGc9QS5yZXNwb25zZVR5cGUsbjtmdW5jdGlvbiBFKCl7QS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShuKSxBLnNpZ25hbCYmQS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG4pfXMuaXNGb3JtRGF0YShyKSYmKEQuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEQuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/aS5zZXRDb250ZW50VHlwZSghMSk6aS5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YTsiLCExKSk7bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IEM9QS5hdXRoLnVzZXJuYW1lfHwiIixRPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoQysiOiIrUSkpfWxldCBCPXJBKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksQUEoQixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIGMoKXtpZighbylyZXR1cm47bGV0IEM9cC5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksZj17ZGF0YTohZ3x8Zz09PSJ0ZXh0Inx8Zz09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOkMsY29uZmlnOkEscmVxdWVzdDpvfTtaQShmdW5jdGlvbih3KXt0KHcpLEUoKX0sZnVuY3Rpb24odyl7SSh3KSxFKCl9LGYpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9YzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoYyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihJKG5ldyBsKCJSZXF1ZXN0IGFib3J0ZWQiLGwuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe0kobmV3IGwoIk5ldHdvcmsgRXJyb3IiLGwuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBRPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixmPUEudHJhbnNpdGlvbmFsfHxtQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihRPUEudGltZW91dEVycm9yTWVzc2FnZSksSShuZXcgbChRLGYuY2xhcmlmeVRpbWVvdXRFcnJvcj9sLkVUSU1FRE9VVDpsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LEQuaXNTdGFuZGFyZEJyb3dzZXJFbnYpe2xldCBDPShBLndpdGhDcmVkZW50aWFsc3x8V2UoQikpJiZBLnhzcmZDb29raWVOYW1lJiZQZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO0MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsQyl9cj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBvJiZzLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihRLGYpe28uc2V0UmVxdWVzdEhlYWRlcihmLFEpfSkscy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChvLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxnJiZnIT09Impzb24iJiYoby5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLnVwbG9hZCYmby51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihuPUM9PntvJiYoSSghQ3x8Qy50eXBlP25ldyBNKG51bGwsQSxvKTpDKSxvLmFib3J0KCksbz1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobiksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP24oKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbikpKTtsZXQgYT16QShCKTtpZihhJiZELnByb3RvY29scy5pbmRleE9mKGEpPT09LTEpe0kobmV3IGwoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrYSsiOiIsbC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1vLnNlbmQocnx8bnVsbCl9KX07dmFyIHBBPXtodHRwOmhBLHhocjpfZX07cy5mb3JFYWNoKHBBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyIFZlPXtnZXRBZGFwdGVyOkE9PntBPXMuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsdCxJO2ZvcihsZXQgcj0wO3I8ZSYmKHQ9QVtyXSwhKEk9cy5pc1N0cmluZyh0KT9wQVt0LnRvTG93ZXJDYXNlKCldOnQpKTtyKyspO2lmKCFJKXRocm93IEk9PT0hMT9uZXcgbChgQWRhcHRlciAke3R9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50YCwiRVJSX05PVF9TVVBQT1JUIik6bmV3IEVycm9yKHMuaGFzT3duUHJvcChwQSx0KT9gQWRhcHRlciBcJyR7dH1cJyBpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZGA6YFVua25vd24gYWRhcHRlciBcJyR7dH1cJ2ApO2lmKCFzLmlzRnVuY3Rpb24oSSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiYWRhcHRlciBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBJfSxhZGFwdGVyczpwQX07ZnVuY3Rpb24gWEEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IE0obnVsbCxBKX1mdW5jdGlvbiBGQShBKXtyZXR1cm4gWEEoQSksQS5oZWFkZXJzPXAuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksVmUuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fGouYWRhcHRlcikoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gWEEoQSksSS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1wLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gSUEoSSl8fChYQShBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1wLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIHplPUE9PkEgaW5zdGFuY2VvZiBwP0EudG9KU09OKCk6QTtmdW5jdGlvbiBrKEEsZSl7ZT1lfHx7fTtsZXQgdD17fTtmdW5jdGlvbiBJKG8sQixjKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KG8pJiZzLmlzUGxhaW5PYmplY3QoQik/cy5tZXJnZS5jYWxsKHtjYXNlbGVzczpjfSxvLEIpOnMuaXNQbGFpbk9iamVjdChCKT9zLm1lcmdlKHt9LEIpOnMuaXNBcnJheShCKT9CLnNsaWNlKCk6Qn1mdW5jdGlvbiByKG8sQixjKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyxjKX1lbHNlIHJldHVybiBJKG8sQixjKX1mdW5jdGlvbiBpKG8sQil7aWYoIXMuaXNVbmRlZmluZWQoQikpcmV0dXJuIEkodm9pZCAwLEIpfWZ1bmN0aW9uIGcobyxCKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyl9ZWxzZSByZXR1cm4gSSh2b2lkIDAsQil9ZnVuY3Rpb24gbihvLEIsYyl7aWYoYyBpbiBlKXJldHVybiBJKG8sQik7aWYoYyBpbiBBKXJldHVybiBJKHZvaWQgMCxvKX1sZXQgRT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsYWRhcHRlcjpnLHJlc3BvbnNlVHlwZTpnLHhzcmZDb29raWVOYW1lOmcseHNyZkhlYWRlck5hbWU6ZyxvblVwbG9hZFByb2dyZXNzOmcsb25Eb3dubG9hZFByb2dyZXNzOmcsZGVjb21wcmVzczpnLG1heENvbnRlbnRMZW5ndGg6ZyxtYXhCb2R5TGVuZ3RoOmcsYmVmb3JlUmVkaXJlY3Q6Zyx0cmFuc3BvcnQ6ZyxodHRwQWdlbnQ6ZyxodHRwc0FnZW50OmcsY2FuY2VsVG9rZW46Zyxzb2NrZXRQYXRoOmcscmVzcG9uc2VFbmNvZGluZzpnLHZhbGlkYXRlU3RhdHVzOm4saGVhZGVyczoobyxCKT0+cih6ZShvKSx6ZShCKSwhMCl9O3JldHVybiBzLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihCKXtsZXQgYz1FW0JdfHxyLGE9YyhBW0JdLGVbQl0sQik7cy5pc1VuZGVmaW5lZChhKSYmYyE9PW58fCh0W0JdPWEpfSksdH12YXIgU0E9IjEuNC4wIjt2YXIgdkE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57dkFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIFhlPXt9O3ZBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQsSSl7ZnVuY3Rpb24gcihpLGcpe3JldHVybiJbQXhpb3MgdiIrU0ErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIraSsiXCciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4oaSxnLG4pPT57aWYoZT09PSExKXRocm93IG5ldyBsKHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksbC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFYZVtnXSYmKFhlW2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKGksZyxuKTohMH19O2Z1bmN0aW9uIG1JKEEsZSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGwoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgaT1JW3JdLGc9ZVtpXTtpZihnKXtsZXQgbj1BW2ldLEU9bj09PXZvaWQgMHx8ZyhuLGksQSk7aWYoRSE9PSEwKXRocm93IG5ldyBsKCJvcHRpb24gIitpKyIgbXVzdCBiZSAiK0UsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyBsKCJVbmtub3duIG9wdGlvbiAiK2ksbC5FUlJfQkFEX09QVElPTil9fXZhciBOQT17YXNzZXJ0T3B0aW9uczptSSx2YWxpZGF0b3JzOnZBfTt2YXIgYj1OQS52YWxpZGF0b3JzLF89Y2xhc3N7Y29uc3RydWN0b3IoZSl7dGhpcy5kZWZhdWx0cz1lLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBQQSxyZXNwb25zZTpuZXcgUEF9fXJlcXVlc3QoZSx0KXt0eXBlb2YgZT09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9ZSk6dD1lfHx7fSx0PWsodGhpcy5kZWZhdWx0cyx0KTtsZXR7dHJhbnNpdGlvbmFsOkkscGFyYW1zU2VyaWFsaXplcjpyLGhlYWRlcnM6aX09dDtJIT09dm9pZCAwJiZOQS5hc3NlcnRPcHRpb25zKEkse3NpbGVudEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Yi50cmFuc2l0aW9uYWwoYi5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbil9LCExKSxyIT1udWxsJiYocy5pc0Z1bmN0aW9uKHIpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9Ok5BLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOmIuZnVuY3Rpb24sc2VyaWFsaXplOmIuZnVuY3Rpb259LCEwKSksdC5tZXRob2Q9KHQubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGc7Zz1pJiZzLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKSxnJiZzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBpW1FdfSksdC5oZWFkZXJzPXAuY29uY2F0KGcsaSk7bGV0IG49W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7dHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITF8fChFPUUmJmYuc3luY2hyb25vdXMsbi51bnNoaWZ0KGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpKX0pO2xldCBvPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZil7by5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IEIsYz0wLGE7aWYoIUUpe2xldCBRPVtGQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKFEudW5zaGlmdC5hcHBseShRLG4pLFEucHVzaC5hcHBseShRLG8pLGE9US5sZW5ndGgsQj1Qcm9taXNlLnJlc29sdmUodCk7YzxhOylCPUIudGhlbihRW2MrK10sUVtjKytdKTtyZXR1cm4gQn1hPW4ubGVuZ3RoO2xldCBDPXQ7Zm9yKGM9MDtjPGE7KXtsZXQgUT1uW2MrK10sZj1uW2MrK107dHJ5e0M9UShDKX1jYXRjaChtKXtmLmNhbGwodGhpcyxtKTticmVha319dHJ5e0I9RkEuY2FsbCh0aGlzLEMpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3IoYz0wLGE9by5sZW5ndGg7YzxhOylCPUIudGhlbihvW2MrK10sb1tjKytdKTtyZXR1cm4gQn1nZXRVcmkoZSl7ZT1rKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9ckEoZS5iYXNlVVJMLGUudXJsKTtyZXR1cm4gQUEodCxlLnBhcmFtcyxlLnBhcmFtc1NlcmlhbGl6ZXIpfX07cy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihlKXtfLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LEkpe3JldHVybiB0aGlzLnJlcXVlc3QoayhJfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChJKXtyZXR1cm4gZnVuY3Rpb24oaSxnLG4pe3JldHVybiB0aGlzLnJlcXVlc3QoayhufHx7fSx7bWV0aG9kOmUsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDppLGRhdGE6Z30pKX19Xy5wcm90b3R5cGVbZV09dCgpLF8ucHJvdG90eXBlW2UrIkZvcm0iXT10KCEwKX0pO3ZhciBpQT1fO3ZhciAkQT1jbGFzcyBBe2NvbnN0cnVjdG9yKGUpe2lmKHR5cGVvZiBlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dD1pfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IGk9SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2ktLSA+MDspSS5fbGlzdGVuZXJzW2ldKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBpLGc9bmV3IFByb21pc2Uobj0+e0kuc3Vic2NyaWJlKG4pLGk9bn0pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShpKX0sZ30sZShmdW5jdGlvbihpLGcsbil7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgTShpLGcsbiksdChJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfXVuc3Vic2NyaWJlKGUpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKGUpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgZTtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24ocil7ZT1yfSksY2FuY2VsOmV9fX0sdmU9JEE7ZnVuY3Rpb24gQWUoQSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBBLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGVlKEEpe3JldHVybiBzLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciB0ZT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXModGUpLmZvckVhY2goKFtBLGVdKT0+e3RlW2VdPUF9KTt2YXIgJGU9dGU7ZnVuY3Rpb24gQXQoQSl7bGV0IGU9bmV3IGlBKEEpLHQ9WChpQS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gcy5leHRlbmQodCxpQS5wcm90b3R5cGUsZSx7YWxsT3duS2V5czohMH0pLHMuZXh0ZW5kKHQsZSxudWxsLHthbGxPd25LZXlzOiEwfSksdC5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIEF0KGsoQSxyKSl9LHR9dmFyIGg9QXQoaik7aC5BeGlvcz1pQTtoLkNhbmNlbGVkRXJyb3I9TTtoLkNhbmNlbFRva2VuPXZlO2guaXNDYW5jZWw9SUE7aC5WRVJTSU9OPVNBO2gudG9Gb3JtRGF0YT1KO2guQXhpb3NFcnJvcj1sO2guQ2FuY2VsPWguQ2FuY2VsZWRFcnJvcjtoLmFsbD1mdW5jdGlvbihlKXtyZXR1cm4gUHJvbWlzZS5hbGwoZSl9O2guc3ByZWFkPUFlO2guaXNBeGlvc0Vycm9yPWVlO2gubWVyZ2VDb25maWc9aztoLkF4aW9zSGVhZGVycz1wO2guZm9ybVRvSlNPTj1BPT5EQShzLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO2guSHR0cFN0YXR1c0NvZGU9JGU7aC5kZWZhdWx0PWg7dmFyIFJBPWg7dmFye0F4aW9zOlNnLEF4aW9zRXJyb3I6TmcsQ2FuY2VsZWRFcnJvcjpSZyxpc0NhbmNlbDpHZyxDYW5jZWxUb2tlbjpVZyxWRVJTSU9OOmtnLGFsbDpMZyxDYW5jZWw6T2csaXNBeGlvc0Vycm9yOkpnLHNwcmVhZDpNZyx0b0Zvcm1EYXRhOmJnLEF4aW9zSGVhZGVyczpIZyxIdHRwU3RhdHVzQ29kZTpZZyxmb3JtVG9KU09OOnFnLG1lcmdlQ29uZmlnOlRnfT1SQTt2YXIgZ0EsTCxyZSxJZT17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe3JlPW5ldyBVaW50OEFycmF5KEwuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSxHQT1jbGFzc3tpbml0KCl7cmV0dXJuIGdBfHwodHlwZW9mIGZldGNoPCJ1Ij9nQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK2V0KS50aGVuKGU9PmUuYXJyYXlCdWZmZXIoKSkudGhlbihlPT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShlLEllKSkudGhlbih0aGlzLl9pbml0KTpnQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbShldCwiYmFzZTY0IiksSWUpLnRoZW4odGhpcy5faW5pdCksZ0EpfV9pbml0KGUpe0w9ZS5pbnN0YW5jZSxJZS5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUoZSx0PTApe2lmKCFMKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBJPWUuYnl0ZUxlbmd0aCxyPUwuZXhwb3J0cy5tYWxsb2MoSSk7cmUuc2V0KGUsciksdD10fHxOdW1iZXIoTC5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUocixJKSk7bGV0IGk9TC5leHBvcnRzLm1hbGxvYyh0KSxnPUwuZXhwb3J0cy5aU1REX2RlY29tcHJlc3MoaSx0LHIsSSksbj1yZS5zbGljZShpLGkrZyk7cmV0dXJuIEwuZXhwb3J0cy5mcmVlKHIpLEwuZXhwb3J0cy5mcmVlKGkpLG59fSxldD0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciB0dD1uZXcgR0EsSXQ9ITE7YXN5bmMgZnVuY3Rpb24gREkoQSxlKXtsZXQgdD1udWxsO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IEk9YCR7dH0ud2FzbWAscj1hd2FpdCBSQS5nZXQoYCR7SX0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KTtJdHx8KGF3YWl0IHR0LmluaXQoKSxJdD0hMCk7bGV0IGc9dHQuZGVjb2RlKG5ldyBVaW50OEFycmF5KHIuZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6Z30pfXZhciBydD1ESTt2YXIgVUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiB5SShBLGUpe2xldCB0PUEsST1BLHI9bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYodD1uZXcgVVJMKEEuaHJlZiksST10LmhyZWYpLFVBLmhhcyhJKXx8VUEuc2V0KEksYXdhaXQgcnQodCxlKSkscj1VQS5nZXQoSSkscn12YXIgRz15STt2YXIgd0k9bmV3IE1hcChbWyJpbWFnZS9qcGVnIiwiSlBFR0ltYWdlSU8iXSxbImltYWdlL3BuZyIsIlBOR0ltYWdlSU8iXSxbImltYWdlL3RpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiaW1hZ2UveC1tcy1ibXAiLCJCTVBJbWFnZUlPIl0sWyJpbWFnZS94LWJtcCIsIkJNUEltYWdlSU8iXSxbImltYWdlL2JtcCIsIkJNUEltYWdlSU8iXSxbImFwcGxpY2F0aW9uL2RpY29tIiwiR0RDTUltYWdlSU8iXV0pLGllPXdJO3ZhciBwST1uZXcgTWFwKFtbImJtcCIsIkJNUEltYWdlSU8iXSxbIkJNUCIsIkJNUEltYWdlSU8iXSxbImRjbSIsIkdEQ01JbWFnZUlPIl0sWyJEQ00iLCJHRENNSW1hZ2VJTyJdLFsiZ2lwbCIsIkdpcGxJbWFnZUlPIl0sWyJnaXBsLmd6IiwiR2lwbEltYWdlSU8iXSxbImhkZjUiLCJIREY1SW1hZ2VJTyJdLFsianBnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRyIsIkpQRUdJbWFnZUlPIl0sWyJqcGVnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRUciLCJKUEVHSW1hZ2VJTyJdLFsiaXdpIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yLnpzdCIsIldhc21ac3RkSW1hZ2VJTyJdLFsibHNtIiwiTFNNSW1hZ2VJTyJdLFsibW5jIiwiTUlOQ0ltYWdlSU8iXSxbIk1OQyIsIk1JTkNJbWFnZUlPIl0sWyJtbmMuZ3oiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DLkdaIiwiTUlOQ0ltYWdlSU8iXSxbIm1uYzIiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DMiIsIk1JTkNJbWFnZUlPIl0sWyJtZ2giLCJNR0hJbWFnZUlPIl0sWyJtZ3oiLCJNR0hJbWFnZUlPIl0sWyJtZ2guZ3oiLCJNR0hJbWFnZUlPIl0sWyJtaGEiLCJNZXRhSW1hZ2VJTyJdLFsibWhkIiwiTWV0YUltYWdlSU8iXSxbIm1yYyIsIk1SQ0ltYWdlSU8iXSxbIm5pYSIsIk5pZnRpSW1hZ2VJTyJdLFsibmlpIiwiTmlmdGlJbWFnZUlPIl0sWyJuaWkuZ3oiLCJOaWZ0aUltYWdlSU8iXSxbImhkciIsIk5pZnRpSW1hZ2VJTyJdLFsibnJyZCIsIk5ycmRJbWFnZUlPIl0sWyJOUlJEIiwiTnJyZEltYWdlSU8iXSxbIm5oZHIiLCJOcnJkSW1hZ2VJTyJdLFsiTkhEUiIsIk5ycmRJbWFnZUlPIl0sWyJwbmciLCJQTkdJbWFnZUlPIl0sWyJQTkciLCJQTkdJbWFnZUlPIl0sWyJwaWMiLCJCaW9SYWRJbWFnZUlPIl0sWyJQSUMiLCJCaW9SYWRJbWFnZUlPIl0sWyJ0aWYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGIiwiVElGRkltYWdlSU8iXSxbInRpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGRiIsIlRJRkZJbWFnZUlPIl0sWyJ2dGsiLCJWVEtJbWFnZUlPIl0sWyJWVEsiLCJWVEtJbWFnZUlPIl0sWyJpc3EiLCJTY2FuY29JbWFnZUlPIl0sWyJJU1EiLCJTY2FuY29JbWFnZUlPIl0sWyJmZGYiLCJGREZJbWFnZUlPIl0sWyJGREYiLCJGREZJbWFnZUlPIl1dKSxnZT1wSTtmdW5jdGlvbiBGSShBKXtsZXQgZT1BLnNsaWNlKChBLmxhc3RJbmRleE9mKCIuIiktMT4+PjApKzIpO2lmKGUudG9Mb3dlckNhc2UoKT09PSJneiIpe2xldCB0PUEuc2xpY2UoMCwtMykubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoZS50b0xvd2VyQ2FzZSgpPT09ImNib3IiKXtsZXQgdD1BLnNsaWNlKDAsLTUpLmxhc3RJbmRleE9mKCIuIik7ZT1BLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKGUudG9Mb3dlckNhc2UoKT09PSJ6c3QiKXtsZXQgdD1BLnNsaWNlKDAsLTEwKS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihlLnRvTG93ZXJDYXNlKCk9PT0iemlwIil7bGV0IHQ9QS5zbGljZSgwLC00KS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9cmV0dXJuIGV9dmFyIGtBPUZJO3ZhciBTST1bIlBOR0ltYWdlSU8iLCJNZXRhSW1hZ2VJTyIsIlRJRkZJbWFnZUlPIiwiTmlmdGlJbWFnZUlPIiwiSlBFR0ltYWdlSU8iLCJOcnJkSW1hZ2VJTyIsIlZUS0ltYWdlSU8iLCJCTVBJbWFnZUlPIiwiSERGNUltYWdlSU8iLCJNSU5DSW1hZ2VJTyIsIk1SQ0ltYWdlSU8iLCJMU01JbWFnZUlPIiwiTUdISW1hZ2VJTyIsIkJpb1JhZEltYWdlSU8iLCJHaXBsSW1hZ2VJTyIsIkdFQWR3SW1hZ2VJTyIsIkdFNEltYWdlSU8iLCJHRTVJbWFnZUlPIiwiR0RDTUltYWdlSU8iLCJTY2FuY29JbWFnZUlPIiwiRkRGSW1hZ2VJTyIsIldhc21JbWFnZUlPIiwiV2FzbVpzdGRJbWFnZUlPIl0sTEE9U0k7dmFyIE5JPXtUZXh0RmlsZToiSW50ZXJmYWNlVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkludGVyZmFjZUJpbmFyeUZpbGUiLFRleHRTdHJlYW06IkludGVyZmFjZVRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiSW50ZXJmYWNlQmluYXJ5U3RyZWFtIixJbWFnZToiSW50ZXJmYWNlSW1hZ2UiLE1lc2g6IkludGVyZmFjZU1lc2giLFBvbHlEYXRhOiJJbnRlcmZhY2VQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6IkludGVyZmFjZUpzb25Db21wYXRpYmxlIn0sdT1OSTt2YXIgUkk9e1RleHQ6IlRleHQiLEJpbmFyeToiQmluYXJ5IixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2gifSxTPVJJO3ZhciBHST17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEY9R0k7dmFyIFVJPXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxUPVVJO2Z1bmN0aW9uIGtJKEEsZSl7bGV0IHQ9bnVsbDtzd2l0Y2goQSl7Y2FzZSBGLlVJbnQ4Ont0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ4Ont0PW5ldyBJbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQxNjp7dD1uZXcgVWludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDE2Ont0PW5ldyBJbnQxNkFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50MzI6e3Q9bmV3IFVpbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQzMjp7dD1uZXcgSW50MzJBcnJheShlKTticmVha31jYXNlIEYuVUludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdVaW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdVaW50NjRBcnJheShlKTp0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnSW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdJbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBULkZsb2F0MzI6e3Q9bmV3IEZsb2F0MzJBcnJheShlKTticmVha31jYXNlIFQuRmxvYXQ2NDp7dD1uZXcgRmxvYXQ2NEFycmF5KGUpO2JyZWFrfWNhc2UibnVsbCI6e3Q9bnVsbDticmVha31jYXNlIG51bGw6e3Q9bnVsbDticmVha31kZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVHlwZSBpcyBub3Qgc3VwcG9ydGVkIGFzIGEgVHlwZWRBcnJheSIpfXJldHVybiB0fXZhciBkPWtJO3ZhciBvdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixpdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoQSxlKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3BlbihlLHQuZmxhZ3MpLGk9QS5mc19zdGF0KGUpLnNpemUsZz1udWxsO290P2c9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGkpOmc9bmV3IEFycmF5QnVmZmVyKGkpO2xldCBuPW5ldyBVaW50OEFycmF5KGcpO3JldHVybiBBLmZzX3JlYWQoSSxuLDAsaSwwKSxBLmZzX2Nsb3NlKEkpLG59ZnVuY3Rpb24gbnQoQSxlLHQpe2xldCBJPW51bGw7b3Q/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ST1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksaT1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsZSx0KTtyZXR1cm4gci5zZXQoaSkscn1mdW5jdGlvbiB5KEEsZSx0LEkpe2xldCByPTA7cmV0dXJuIGUhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEksZS5idWZmZXIuYnl0ZUxlbmd0aF0pLEEuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShlLmJ1ZmZlcikscikpLHJ9ZnVuY3Rpb24gVihBLGUsdCl7bGV0IEk9SlNPTi5zdHJpbmdpZnkoZSkscj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsSS5sZW5ndGhdKTtBLndyaXRlQXNjaWlUb01lbW9yeShJLHIsITEpfWZ1bmN0aW9uIE4oQSxlLHQsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksaT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxnPW50KEEscixpKTtyZXR1cm4gZChJLGcuYnVmZmVyKX1mdW5jdGlvbiBvZShBLGUpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsZV0pLEk9QS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKEkpfWZ1bmN0aW9uIExJKEEsZSx0LEkpe0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihvLEIpe3ZhciBjO3N3aXRjaChvLnR5cGUpe2Nhc2UgdS5UZXh0U3RyZWFtOntsZXQgYT1pdC5lbmNvZGUoby5kYXRhLmRhdGEpLEM9eShBLGEsQiwwKSxRPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07VihBLFEsQik7YnJlYWt9Y2FzZSB1Lkpzb25Db21wYXRpYmxlOntsZXQgYT1pdC5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoby5kYXRhKSksQz15KEEsYSxCLDApLFE9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTtWKEEsUSxCKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgYT1vLmRhdGEuZGF0YSxDPXkoQSxhLEIsMCksUT17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1YoQSxRLEIpO2JyZWFrfWNhc2UgdS5UZXh0RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgdS5CaW5hcnlGaWxlOntBLmZzX3dyaXRlRmlsZShvLmRhdGEucGF0aCxvLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSB1LkltYWdlOntsZXQgYT1vLmRhdGEsQz15KEEsYS5kYXRhLEIsMCksUT15KEEsYS5kaXJlY3Rpb24sQiwxKSxmPXR5cGVvZigoYz1hLm1ldGFkYXRhKT09PW51bGx8fGM9PT12b2lkIDA/dm9pZCAwOmMuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20oYS5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLG09e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLHNpemU6YS5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsbWV0YWRhdGE6Zn07VihBLG0sQik7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBhPW8uZGF0YSxDPXkoQSxhLnBvaW50cyxCLDApLFE9eShBLGEuY2VsbHMsQiwxKSxmPXkoQSxhLnBvaW50RGF0YSxCLDIpLG09eShBLGEuY2VsbERhdGEsQiwzKSx3PXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YH07VihBLHcsQik7YnJlYWt9Y2FzZSB1LlBvbHlEYXRhOntsZXQgYT1vLmRhdGEsQz15KEEsYS5wb2ludHMsQiwwKSxRPXkoQSxhLnZlcnRpY2VzLEIsMSksZj15KEEsYS5saW5lcyxCLDIpLG09eShBLGEucG9seWdvbnMsQiwzKSx3PXkoQSxhLnRyaWFuZ2xlU3RyaXBzLEIsNCksTz15KEEsYS5wb2ludERhdGEsQiw1KSxLPXkoQSxhLnBvaW50RGF0YSxCLDYpLEpBPXtwb2x5RGF0YVR5cGU6YS5wb2x5RGF0YVR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsdmVydGljZXNCdWZmZXJTaXplOmEudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGxpbmVzQnVmZmVyU2l6ZTphLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxwb2x5Z29uc0J1ZmZlclNpemU6YS5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOmEudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7d31gLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke099YCxudW1iZXJPZkNlbGxQaXhlbHM6YS5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtLfWB9O1YoQSxKQSxCKTticmVha31jYXNlIFMuVGV4dDp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkJpbmFyeTp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkltYWdlOntsZXQgYT1vLmRhdGEsQz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTphLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoQykpLGEuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5kYXRhLmJ1ZmZlcikpLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShhLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFMuTWVzaDp7bGV0IGE9by5kYXRhLEM9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZX07aWYoQS5mc19ta2RpcnMoYCR7by5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShDKSksQy5udW1iZXJPZlBvaW50cz4wKXtpZihhLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5wb2ludHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKGEucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShhLnBvaW50RGF0YS5idWZmZXIpKX1pZihDLm51bWJlck9mQ2VsbHM+MCl7aWYoYS5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYoYS5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLEEucmVzZXRNb2R1bGVTdGRvdXQoKSxBLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IHI9QS5zdGFja1NhdmUoKSxpPTA7dHJ5e2k9QS5jYWxsTWFpbihlLnNsaWNlKCkpfWNhdGNoKG8pe3Rocm93IHR5cGVvZiBvPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsQS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsQS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIEEuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsQS5nZXRFeGNlcHRpb25NZXNzYWdlKG8pKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLG99ZmluYWxseXtBLnN0YWNrUmVzdG9yZShyKX1sZXQgZz1BLmdldE1vZHVsZVN0ZG91dCgpLG49QS5nZXRNb2R1bGVTdGRlcnIoKSxFPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZpPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKG8sQil7bGV0IGM9bnVsbDtzd2l0Y2goby50eXBlKXtjYXNlIHUuVGV4dFN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLFEpO2M9e2RhdGE6Z3QuZGVjb2RlKGYpfTticmVha31jYXNlIHUuSnNvbkNvbXBhdGlibGU6e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksZj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsQyxRKTtjPUpTT04ucGFyc2UoZ3QuZGVjb2RlKGYpKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pO2M9e2RhdGE6bnQoQSxDLFEpfTticmVha31jYXNlIHUuVGV4dEZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpBLmZzX3JlYWRGaWxlKG8uZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSB1LkJpbmFyeUZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpIKEEsby5kYXRhLnBhdGgpfTticmVha31jYXNlIHUuSW1hZ2U6e2xldCBDPW9lKEEsQik7Qy5kYXRhPU4oQSxCLDAsQy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQy5kaXJlY3Rpb249TihBLEIsMSxULkZsb2F0NjQpLEMubWV0YWRhdGE9bmV3IE1hcChDLm1ldGFkYXRhKSxjPUM7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkMucG9pbnRzPWQoQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbHM+MD9DLmNlbGxzPU4oQSxCLDEsQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qy5jZWxscz1kKEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiwyLEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPWQoQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1OKEEsQiwzLEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGM9QzticmVha31jYXNlIHUuUG9seURhdGE6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsVC5GbG9hdDMyKTpDLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEMudmVydGljZXNCdWZmZXJTaXplPjA/Qy52ZXJ0aWNlcz1OKEEsQiwxLEYuVUludDMyKTpDLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxDLmxpbmVzQnVmZmVyU2l6ZT4wP0MubGluZXM9TihBLEIsMixGLlVJbnQzMik6Qy5saW5lcz1uZXcgVWludDMyQXJyYXksQy5wb2x5Z29uc0J1ZmZlclNpemU+MD9DLnBvbHlnb25zPU4oQSxCLDMsRi5VSW50MzIpOkMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qy50cmlhbmdsZVN0cmlwcz1OKEEsQiw0LEYuVUludDMyKTpDLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiw1LEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpDLnBvaW50RGF0YT1kKEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxQaXhlbHM+MD9DLmNlbGxEYXRhPU4oQSxCLDYsQy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxjPUM7YnJlYWt9Y2FzZSBTLlRleHQ6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtjPUEuZnNfcmVhZEZpbGUoby5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFMuQmluYXJ5OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Yz1IKEEsby5wYXRoKTticmVha31jYXNlIFMuSW1hZ2U6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgQz1BLmZzX3JlYWRGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLFE9SlNPTi5wYXJzZShDKSxmPUgoQSxgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtRLmRhdGE9ZChRLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGYuYnVmZmVyKTtsZXQgbT1IKEEsYCR7by5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtRLmRpcmVjdGlvbj1kKFQuRmxvYXQ2NCxtLmJ1ZmZlciksYz1RO2JyZWFrfWNhc2UgUy5NZXNoOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEM9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxRPUpTT04ucGFyc2UoQyk7aWYoUS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtRLnBvaW50cz1kKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnRzPWQoUS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihRLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7US5wb2ludERhdGE9ZChRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnREYXRhPWQoUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKFEubnVtYmVyT2ZDZWxscz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO1EuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoUS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtRLmNlbGxEYXRhPWQoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbERhdGE9ZChRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtjPVE7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgYT17dHlwZTpvLnR5cGUsZGF0YTpjfTtFLnB1c2goYSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6ZyxzdGRlcnI6bixvdXRwdXRzOkV9fXZhciB6PUxJO3ZhciBvQT1mdW5jdGlvbihBKXtyZXR1cm4gdGhpcyBpbnN0YW5jZW9mIG9BPyh0aGlzLnY9QSx0aGlzKTpuZXcgb0EoQSl9LE9JPWZ1bmN0aW9uKEEsZSx0KXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIEk9dC5hcHBseShBLGV8fFtdKSxyLGk9W107cmV0dXJuIHI9e30sZygibmV4dCIpLGcoInRocm93IiksZygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scjtmdW5jdGlvbiBnKGEpe0lbYV0mJihyW2FdPWZ1bmN0aW9uKEMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihRLGYpe2kucHVzaChbYSxDLFEsZl0pPjF8fG4oYSxDKX0pfSl9ZnVuY3Rpb24gbihhLEMpe3RyeXtFKElbYV0oQykpfWNhdGNoKFEpe2MoaVswXVszXSxRKX19ZnVuY3Rpb24gRShhKXthLnZhbHVlIGluc3RhbmNlb2Ygb0E/UHJvbWlzZS5yZXNvbHZlKGEudmFsdWUudikudGhlbihvLEIpOmMoaVswXVsyXSxhKX1mdW5jdGlvbiBvKGEpe24oIm5leHQiLGEpfWZ1bmN0aW9uIEIoYSl7bigidGhyb3ciLGEpfWZ1bmN0aW9uIGMoYSxDKXthKEMpLGkuc2hpZnQoKSxpLmxlbmd0aCYmbihpWzBdWzBdLGlbMF1bMV0pfX0sSkk9ZnVuY3Rpb24oQSl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBlPUFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdLHQ7cmV0dXJuIGU/ZS5jYWxsKEEpOihBPXR5cGVvZiBfX3ZhbHVlcz09ImZ1bmN0aW9uIj9fX3ZhbHVlcyhBKTpBW1N5bWJvbC5pdGVyYXRvcl0oKSx0PXt9LEkoIm5leHQiKSxJKCJ0aHJvdyIpLEkoInJldHVybiIpLHRbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHQpO2Z1bmN0aW9uIEkoaSl7dFtpXT1BW2ldJiZmdW5jdGlvbihnKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obixFKXtnPUFbaV0oZykscihuLEUsZy5kb25lLGcudmFsdWUpfSl9fWZ1bmN0aW9uIHIoaSxnLG4sRSl7UHJvbWlzZS5yZXNvbHZlKEUpLnRoZW4oZnVuY3Rpb24obyl7aSh7dmFsdWU6byxkb25lOm59KX0sZyl9fTtmdW5jdGlvbiBNSShBKXtyZXR1cm4gT0kodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24qKCl7Zm9yKGxldCB0PTA7dDxMQS5sZW5ndGg7dCsrKXtsZXQgST1MQVt0XSsiLXJlYWQtaW1hZ2UiLHI9eWllbGQgb0EoRyhJLEEuY29uZmlnLmltYWdlSU9VcmwpKTt5aWVsZCB5aWVsZCBvQShyKX19KX1hc3luYyBmdW5jdGlvbiBiSShBLGUpe3ZhciB0LEk7aWYoQS5taW1lVHlwZSYmaWUuaGFzKEEubWltZVR5cGUpKXtsZXQgbj1pZS5nZXQoQS5taW1lVHlwZSkrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLmltYWdlSU9VcmwpfWxldCByPWtBKEEuZmlsZU5hbWUpO2lmKGdlLmhhcyhyKSl7bGV0IG49Z2UuZ2V0KHIpK2U7cmV0dXJuIGF3YWl0IEcobixBLmNvbmZpZy5pbWFnZUlPVXJsKX1mb3IobGV0IG49MDtuPExBLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsSkkoTUkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBuZT1iSTt2YXIgSEk9bmV3IE1hcChbXSksYWU9SEk7dmFyIFlJPW5ldyBNYXAoW1sidnRrIiwiVlRLUG9seURhdGFNZXNoSU8iXSxbIlZUSyIsIlZUS1BvbHlEYXRhTWVzaElPIl0sWyJieXUiLCJCWVVNZXNoSU8iXSxbIkJZVSIsIkJZVU1lc2hJTyJdLFsiZnNhIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIl0sWyJGU0EiLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iXSxbImZzYiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIkZTQiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIm9iaiIsIk9CSk1lc2hJTyJdLFsiT0JKIiwiT0JKTWVzaElPIl0sWyJvZmYiLCJPRkZNZXNoSU8iXSxbIk9GRiIsIk9GRk1lc2hJTyJdLFsic3RsIiwiU1RMTWVzaElPIl0sWyJTVEwiLCJTVExNZXNoSU8iXSxbInN3YyIsIlNXQ01lc2hJTyJdLFsiU1dDIiwiU1dDTWVzaElPIl0sWyJpd20iLCJXYXNtTWVzaElPIl0sWyJpd20uY2JvciIsIldhc21NZXNoSU8iXSxbIml3bS5jYm9yLnpzdCIsIldhc21ac3RkTWVzaElPIl1dKSxzZT1ZSTt2YXIgcUk9WyJCWVVNZXNoSU8iLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIiwiT0JKTWVzaElPIiwiT0ZGTWVzaElPIiwiU1RMTWVzaElPIiwiU1dDTWVzaElPIiwiVlRLUG9seURhdGFNZXNoSU8iLCJXYXNtTWVzaElPIiwiV2FzbVpzdGRNZXNoSU8iXSxPQT1xSTt2YXIgbkE9ZnVuY3Rpb24oQSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBuQT8odGhpcy52PUEsdGhpcyk6bmV3IG5BKEEpfSxUST1mdW5jdGlvbihBLGUsdCl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBJPXQuYXBwbHkoQSxlfHxbXSkscixpPVtdO3JldHVybiByPXt9LGcoIm5leHQiKSxnKCJ0aHJvdyIpLGcoInJldHVybiIpLHJbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHI7ZnVuY3Rpb24gZyhhKXtJW2FdJiYoclthXT1mdW5jdGlvbihDKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oUSxmKXtpLnB1c2goW2EsQyxRLGZdKT4xfHxuKGEsQyl9KX0pfWZ1bmN0aW9uIG4oYSxDKXt0cnl7RShJW2FdKEMpKX1jYXRjaChRKXtjKGlbMF1bM10sUSl9fWZ1bmN0aW9uIEUoYSl7YS52YWx1ZSBpbnN0YW5jZW9mIG5BP1Byb21pc2UucmVzb2x2ZShhLnZhbHVlLnYpLnRoZW4obyxCKTpjKGlbMF1bMl0sYSl9ZnVuY3Rpb24gbyhhKXtuKCJuZXh0IixhKX1mdW5jdGlvbiBCKGEpe24oInRocm93IixhKX1mdW5jdGlvbiBjKGEsQyl7YShDKSxpLnNoaWZ0KCksaS5sZW5ndGgmJm4oaVswXVswXSxpWzBdWzFdKX19LEtJPWZ1bmN0aW9uKEEpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgZT1BW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSx0O3JldHVybiBlP2UuY2FsbChBKTooQT10eXBlb2YgX192YWx1ZXM9PSJmdW5jdGlvbiI/X192YWx1ZXMoQSk6QVtTeW1ib2wuaXRlcmF0b3JdKCksdD17fSxJKCJuZXh0IiksSSgidGhyb3ciKSxJKCJyZXR1cm4iKSx0W1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0KTtmdW5jdGlvbiBJKGkpe3RbaV09QVtpXSYmZnVuY3Rpb24oZyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4sRSl7Zz1BW2ldKGcpLHIobixFLGcuZG9uZSxnLnZhbHVlKX0pfX1mdW5jdGlvbiByKGksZyxuLEUpe1Byb21pc2UucmVzb2x2ZShFKS50aGVuKGZ1bmN0aW9uKG8pe2koe3ZhbHVlOm8sZG9uZTpufSl9LGcpfX07ZnVuY3Rpb24geEkoQSl7cmV0dXJuIFRJKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKigpe2ZvcihsZXQgdD0wO3Q8T0EubGVuZ3RoO3QrKyl7bGV0IEk9T0FbdF0rIi1yZWFkLW1lc2giLHI9eWllbGQgbkEoRyhJLEEuY29uZmlnLm1lc2hJT1VybCkpO3lpZWxkIHlpZWxkIG5BKHIpfX0pfWFzeW5jIGZ1bmN0aW9uIFBJKEEsZSl7dmFyIHQsSTtpZihBLm1pbWVUeXBlJiZhZS5oYXMoQS5taW1lVHlwZSkpe2xldCBuPWFlLmdldChBLm1pbWVUeXBlKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1sZXQgcj1rQShBLmZpbGVOYW1lKTtpZihzZS5oYXMocikpe2xldCBuPXNlLmdldChyKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1mb3IobGV0IG49MDtuPE9BLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsS0koeEkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBDZT1QSTt2YXIgV0k9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIGpJKEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCB0PTA7dDxBLmxlbmd0aDt0Kyspe2xldCBJPVpJKEFbdF0pO0khPT1udWxsJiZlLnB1c2goSSl9cmV0dXJuIGV9ZnVuY3Rpb24gWkkoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgZT1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD9lPUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKGU9QSksV0kmJmUgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmV9dmFyIGF0PWpJO2Z1bmN0aW9uIF9JKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciBCZT1fSTtmdW5jdGlvbiBWSShBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgUWU9Vkk7ZnVuY3Rpb24gekkoQSl7cmV0dXJuW0EucG9pbnRzLEEudmVydGljZXMsQS5saW5lcyxBLnBvbHlnb25zLEEudHJpYW5nbGVTdHJpcHMsQS5wb2ludERhdGEsQS5jZWxsRGF0YV19dmFyIHN0PXpJO2FzeW5jIGZ1bmN0aW9uIFhJKEEsZSx0LEkpe2xldCByPXooQSxlLHQsSSksaT1bXTtyZXR1cm4gci5vdXRwdXRzJiZyLm91dHB1dHMuZm9yRWFjaChmdW5jdGlvbihnKXtpZihnLnR5cGU9PT11LkJpbmFyeVN0cmVhbXx8Zy50eXBlPT09dS5CaW5hcnlGaWxlKXtsZXQgbj1nLmRhdGE7aS5wdXNoKG4pfWVsc2UgaWYoZy50eXBlPT09dS5JbWFnZSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5CZShuKSl9ZWxzZSBpZihnLnR5cGU9PT11Lk1lc2gpe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uUWUobikpfWVsc2UgaWYoZy50eXBlPT09dS5Qb2x5RGF0YSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5zdChuKSl9ZWxzZSBpZihnLnR5cGU9PT1TLkJpbmFyeSl7bGV0IG49Zy5kYXRhO2kucHVzaChuKX1lbHNlIGlmKGcudHlwZT09PVMuSW1hZ2Upe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uQmUobikpfWVsc2UgaWYoZy50eXBlPT09Uy5NZXNoKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLlFlKG4pKX19KSxIQShyLGF0KGkpKX12YXIgWT1YSTt2YXIgdkk9e21lc2hUb1BvbHlEYXRhOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkpe2xldCByPWF3YWl0IEcoIm1lc2gtdG8tcG9seWRhdGEiLEEubWVzaElPVXJsKTtyZXR1cm4gWShyLGUsdCxJKX0scG9seURhdGFUb01lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSl7bGV0IHI9YXdhaXQgRygicG9seWRhdGEtdG8tbWVzaCIsQS5tZXNoSU9VcmwpO3JldHVybiBZKHIsZSx0LEkpfSxyZWFkSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi1yZWFkLWltYWdlIik7cmV0dXJuIFkoZyxJLHIsaSl9LHdyaXRlSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1pbWFnZSIpO3JldHVybiBZKGcsSSxyLGkpfSxyZWFkTWVzaDphc3luYyBmdW5jdGlvbihBLGUsdCxJLHIsaSl7bGV0IGc9YXdhaXQgQ2Uoe2ZpbGVOYW1lOnQsbWltZVR5cGU6ZSxjb25maWc6QSxhcmdzOkksb3V0cHV0czpyLGlucHV0czppfSwiLXJlYWQtbWVzaCIpO3JldHVybiBZKGcsSSxyLGkpfSx3cml0ZU1lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IENlKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1tZXNoIik7cmV0dXJuIFkoZyxJLHIsaSl9LHJ1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz10eXBlb2YgQVt0XT4idSI/dDpBW3RdLG49YXdhaXQgRyhlLGcpO3JldHVybiBZKG4sSSxyLGkpfX07RUEodkkpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7aXQob3QpO2V4cG9ydHtNciBhcyBjb21wcmVzc1N0cmluZ2lmeSxEQSBhcyBnZXRQaXBlbGluZVdvcmtlclVybCx3QSBhcyBnZXRQaXBlbGluZXNCYXNlVXJsLEhyIGFzIHBhcnNlU3RyaW5nRGVjb21wcmVzcyxpdCBhcyBzZXRQaXBlbGluZVdvcmtlclVybCxGYSBhcyBzZXRQaXBlbGluZXNCYXNlVXJsfTsKLyohIEJ1bmRsZWQgbGljZW5zZSBpbmZvcm1hdGlvbjoKCmNvbWxpbmsvZGlzdC9lc20vY29tbGluay5tanM6CiAgKCoqCiAgICogQGxpY2Vuc2UKICAgKiBDb3B5cmlnaHQgMjAxOSBHb29nbGUgTExDCiAgICogU1BEWC1MaWNlbnNlLUlkZW50aWZpZXI6IEFwYWNoZS0yLjAKICAgKikKKi8K""" +default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/pyproject.toml b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/pyproject.toml index 0ea68688f..496b77c46 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/pyproject.toml +++ b/packages/compress-stringify/python/itkwasm-compress-stringify-emscripten/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] keywords = [ "itkwasm", @@ -31,7 +32,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", ] [project.urls] diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py b/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py index 5becc17c0..159d48b87 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify-wasi/itkwasm_compress_stringify_wasi/_version.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "2.0.1" diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py b/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py index 5becc17c0..159d48b87 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py +++ b/packages/compress-stringify/python/itkwasm-compress-stringify/itkwasm_compress_stringify/_version.py @@ -1 +1 @@ -__version__ = "1.0.0" +__version__ = "2.0.1" diff --git a/packages/compress-stringify/python/itkwasm-compress-stringify/pyproject.toml b/packages/compress-stringify/python/itkwasm-compress-stringify/pyproject.toml index 489e4fc63..2f378e002 100644 --- a/packages/compress-stringify/python/itkwasm-compress-stringify/pyproject.toml +++ b/packages/compress-stringify/python/itkwasm-compress-stringify/pyproject.toml @@ -23,6 +23,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] keywords = [ "itkwasm", @@ -33,7 +34,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", "itkwasm-compress-stringify-wasi; sys_platform != \"emscripten\"", "itkwasm-compress-stringify-emscripten; sys_platform == \"emscripten\"", ] diff --git a/packages/compress-stringify/typescript/package.json b/packages/compress-stringify/typescript/package.json index 0cc9ad9ed..7a8247cfd 100644 --- a/packages/compress-stringify/typescript/package.json +++ b/packages/compress-stringify/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@itk-wasm/compress-stringify", - "version": "1.0.0", + "version": "2.0.1", "description": "Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.", "type": "module", "module": "./dist/index.js", @@ -25,9 +25,9 @@ "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:browser:webWorkers && npm run build:browser:workerEmbedded && npm run build:demo", - "build:browser:webWorkers": "shx mkdir -p dist/web-workers && shx cp node_modules/itk-wasm/dist/core/web-workers/bundles/* ./dist/web-workers/", - "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/compress-stringify-worker-embedded.js ./src/index-worker-embedded.ts", + "build": "npm run build:tsc && npm run build:browser:workerEmbedded && npm run build:browser:workerEmbeddedMin && npm run build:demo", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build:browser:workerEmbeddedMin": "esbuild --minify --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.min.js ./src/index-worker-embedded.min.ts", "build:tsc": "tsc --pretty", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" }, @@ -39,7 +39,7 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.152" + "itk-wasm": "^1.0.0-b.154" }, "devDependencies": { "@shoelace-style/shoelace": "^2.5.2", diff --git a/packages/compress-stringify/typescript/pnpm-lock.yaml b/packages/compress-stringify/typescript/pnpm-lock.yaml index 8ab8d1f5f..d8f52664f 100644 --- a/packages/compress-stringify/typescript/pnpm-lock.yaml +++ b/packages/compress-stringify/typescript/pnpm-lock.yaml @@ -6,8 +6,8 @@ settings: dependencies: itk-wasm: - specifier: ^1.0.0-b.152 - version: 1.0.0-b.152 + specifier: ^1.0.0-b.154 + version: 1.0.0-b.154 devDependencies: '@shoelace-style/shoelace': @@ -1083,6 +1083,10 @@ packages: dependencies: delayed-stream: 1.0.0 + /comlink@4.4.1: + resolution: {integrity: sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==} + dev: false + /commander@6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} engines: {node: '>= 6'} @@ -1904,21 +1908,21 @@ packages: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} dev: true - /itk-wasm@1.0.0-b.152: - resolution: {integrity: sha512-AtOy2iLY/lK9s4rzyeB4l9awJKZSFcQjlyfRcl+33DHcuvRDnpvGR2cgD/KEfiXa/7bZh7rg7+NPca4NgYpZ3g==} + /itk-wasm@1.0.0-b.154: + resolution: {integrity: sha512-bzwOpA4kaNNC2SUTk2wWfHdg+4G6kW8KdMcp3kChhKWzR3T76bV9yybDsuoYq/6aWFQtIgEJLMFcTUpwk0PodA==} hasBin: true dependencies: '@babel/runtime': 7.23.2 '@thewtex/zstddec': 0.2.0 '@types/emscripten': 1.39.9 axios: 1.6.0 + comlink: 4.4.1 commander: 9.5.0 fs-extra: 10.1.0 glob: 8.1.0 markdown-table: 3.0.3 mime-types: 2.1.35 wasm-feature-detect: 1.6.1 - webworker-promise: 0.4.4 transitivePeerDependencies: - debug dev: false @@ -2916,10 +2920,6 @@ packages: resolution: {integrity: sha512-R1i9ED8UlLu/foILNB1ck9XS63vdtqU/tP1MCugVekETp/ySCrBZRk5I/zI67cI1wlQYeSonNm1PLjDHZDNg6g==} dev: false - /webworker-promise@0.4.4: - resolution: {integrity: sha512-NfdSlaWqd+0iSrQudB0N0MELfJ9TVTlynhXMpi06piuZhyc9Yy7Hz6BFu2HUkvIb9lCS0pFW42ptd/JnXVnptg==} - dev: false - /well-known-symbols@2.0.0: resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} engines: {node: '>=6'} diff --git a/packages/compress-stringify/typescript/src/index-worker-embedded.min.ts b/packages/compress-stringify/typescript/src/index-worker-embedded.min.ts new file mode 100644 index 000000000..737584dee --- /dev/null +++ b/packages/compress-stringify/typescript/src/index-worker-embedded.min.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.min.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' From f3d016c04480f19f1f93161e5683f8221bf3a713 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 8 Nov 2023 15:46:16 -0500 Subject: [PATCH 20/23] build(compare-images): bump typescript for itk-wasm 1.0.0-b.154 --- .../_version.py | 2 +- .../js_package.py | 6 +- .../pyproject.toml | 1 + .../test/fixtures.py | 5 +- .../test/test_compare_images_async.py | 44 +- .../itkwasm_compare_images_wasi/_version.py | 2 +- .../itkwasm_compare_images/_version.py | 2 +- .../itkwasm-compare-images/test/fixtures.py | 5 +- .../test/test_compare_images_async.py | 42 +- .../typescript/build/rollup.browser.config.js | 49 - .../typescript/build/rollup.node.config.js | 36 - .../typescript/build/vite.config.js | 2 +- .../compare-images/typescript/package.json | 31 +- .../compare-images/typescript/pnpm-lock.yaml | 2765 +++++++++++++++++ .../src/index-worker-embedded.min.ts | 9 + .../typescript/src/index-worker-embedded.ts | 9 + .../compare-images/typescript/src/index.ts | 1 + .../typescript/src/package.json | 1 + .../typescript/src/pipeline-worker-url.ts | 4 +- .../typescript/src/pipelines-base-url.ts | 2 +- .../compare-images/typescript/tsconfig.json | 8 +- 21 files changed, 2877 insertions(+), 149 deletions(-) delete mode 100644 packages/compare-images/typescript/build/rollup.browser.config.js delete mode 100644 packages/compare-images/typescript/build/rollup.node.config.js create mode 100644 packages/compare-images/typescript/pnpm-lock.yaml create mode 100644 packages/compare-images/typescript/src/index-worker-embedded.min.ts create mode 100644 packages/compare-images/typescript/src/index-worker-embedded.ts create mode 120000 packages/compare-images/typescript/src/package.json diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py index 055276878..ce1305bf4 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py @@ -1 +1 @@ -__version__ = "3.0.1" +__version__ = "4.0.0" diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py index ae6fb28b4..9356f80c7 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py @@ -1,6 +1,8 @@ +# Generated file. To retain edits, remove this comment. + from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ - -default_config = JsPackageConfig(f"https://cdn.jsdelivr.net/npm/@itk-wasm/compare-images@{__version__}/dist/index.js") +default_js_module = """data:text/javascript;base64,dmFyIHB0PU9iamVjdC5kZWZpbmVQcm9wZXJ0eTt2YXIgbXQ9KEEsZSk9Pntmb3IodmFyIHQgaW4gZSlwdChBLHQse2dldDplW3RdLGVudW1lcmFibGU6ITB9KX07dmFyIGh0PSIxLjAuMC1iLjE1NCIsVj1odDt2YXIgeXQ9e3BpcGVsaW5lV29ya2VyVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay13YXNtQCR7Vn0vZGlzdC9jb3JlL3dlYi13b3JrZXJzL2J1bmRsZXMvcGlwZWxpbmUubWluLndvcmtlci5qc2AsaW1hZ2VJT1VybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstaW1hZ2UtaW9AJHtWfWAsbWVzaElPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1tZXNoLWlvQCR7Vn1gLHBpcGVsaW5lc1VybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstd2FzbUAke1Z9L2Rpc3QvcGlwZWxpbmVzYH0sWT15dDt2YXIgd3Q9e1RleHRGaWxlOiJJbnRlcmZhY2VUZXh0RmlsZSIsQmluYXJ5RmlsZToiSW50ZXJmYWNlQmluYXJ5RmlsZSIsVGV4dFN0cmVhbToiSW50ZXJmYWNlVGV4dFN0cmVhbSIsQmluYXJ5U3RyZWFtOiJJbnRlcmZhY2VCaW5hcnlTdHJlYW0iLEltYWdlOiJJbnRlcmZhY2VJbWFnZSIsTWVzaDoiSW50ZXJmYWNlTWVzaCIsUG9seURhdGE6IkludGVyZmFjZVBvbHlEYXRhIixKc29uQ29tcGF0aWJsZToiSW50ZXJmYWNlSnNvbkNvbXBhdGlibGUifSxkPXd0O3ZhciBEdD17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LFE9RHQ7dmFyIGJ0PXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxEPWJ0O3ZhciBTdD17VGV4dDoiVGV4dCIsQmluYXJ5OiJCaW5hcnkiLEltYWdlOiJJbWFnZSIsTWVzaDoiTWVzaCJ9LFU9U3Q7dmFyIEZ0PXtVbmtub3duOiJVbmtub3duIixTY2FsYXI6IlNjYWxhciIsUkdCOiJSR0IiLFJHQkE6IlJHQkEiLE9mZnNldDoiT2Zmc2V0IixWZWN0b3I6IlZlY3RvciIsUG9pbnQ6IlBvaW50IixDb3ZhcmlhbnRWZWN0b3I6IkNvdmFyaWFudFZlY3RvciIsU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvcjoiU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvciIsRGlmZnVzaW9uVGVuc29yM0Q6IkRpZmZ1c2lvblRlbnNvcjNEIixDb21wbGV4OiJDb21wbGV4IixGaXhlZEFycmF5OiJGaXhlZEFycmF5IixBcnJheToiQXJyYXkiLE1hdHJpeDoiTWF0cml4IixWYXJpYWJsZUxlbmd0aFZlY3RvcjoiVmFyaWFibGVMZW5ndGhWZWN0b3IiLFZhcmlhYmxlU2l6ZU1hdHJpeDoiVmFyaWFibGVTaXplTWF0cml4In0sUj1GdDtmdW5jdGlvbiBrdChBLGUsdCxyLG4pe0Fbcit0KmVdPW59dmFyIEllPWt0O3ZhciBGQT1jbGFzc3tjb25zdHJ1Y3RvcihlPTIsdD1RLlVJbnQ4LHI9Ui5TY2FsYXIsbj0xKXt0aGlzLmRpbWVuc2lvbj1lLHRoaXMuY29tcG9uZW50VHlwZT10LHRoaXMucGl4ZWxUeXBlPXIsdGhpcy5jb21wb25lbnRzPW59fSxnZT1GQTt2YXIga0E9Y2xhc3N7Y29uc3RydWN0b3IoZT1uZXcgZ2Upe3RoaXMuaW1hZ2VUeXBlPWUsdGhpcy5uYW1lPSJpbWFnZSI7bGV0IHQ9ZS5kaW1lbnNpb247dGhpcy5vcmlnaW49bmV3IEFycmF5KHQpLHRoaXMub3JpZ2luLmZpbGwoMCksdGhpcy5zcGFjaW5nPW5ldyBBcnJheSh0KSx0aGlzLnNwYWNpbmcuZmlsbCgxKSx0aGlzLmRpcmVjdGlvbj1uZXcgRmxvYXQ2NEFycmF5KHQqdCksdGhpcy5kaXJlY3Rpb24uZmlsbCgwKTtmb3IobGV0IHI9MDtyPHQ7cisrKUllKHRoaXMuZGlyZWN0aW9uLHQscixyLDEpO3RoaXMuc2l6ZT1uZXcgQXJyYXkodCksdGhpcy5zaXplLmZpbGwoMCksdGhpcy5tZXRhZGF0YT1uZXcgTWFwLHRoaXMuZGF0YT1udWxsfX0sbGU9a0E7ZnVuY3Rpb24gVXQoQSxlKXtsZXQgdD1udWxsO3N3aXRjaChBKXtjYXNlIFEuVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBRLkludDg6e3Q9bmV3IEludDhBcnJheShlKTticmVha31jYXNlIFEuVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShlKTticmVha31jYXNlIFEuSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBRLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBRLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgUS5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBRLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIEQuRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRC5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoZSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIGI9VXQ7ZnVuY3Rpb24gUnQoQSxlKXtsZXQgdD1PYmplY3QuYXNzaWduKHt9LEEuaW1hZ2VUeXBlKTtpZih0eXBlb2YgZTwidSImJnR5cGVvZiBlLnBpeGVsVHlwZTwidSImJih0LnBpeGVsVHlwZT1lLnBpeGVsVHlwZSxlLnBpeGVsVHlwZT09PVIuU2NhbGFyJiZ0LmNvbXBvbmVudHMhPT0xKSl0aHJvdyBuZXcgRXJyb3IoIkNhbm5vdCBjYXN0IG11bHRpLWNvbXBvbmVudCBpbWFnZSB0byBhIHNjYWxhciBpbWFnZSIpO3R5cGVvZiBlPCJ1IiYmdHlwZW9mIGUuY29tcG9uZW50VHlwZTwidSImJmUuY29tcG9uZW50VHlwZSE9PUEuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUmJih0LmNvbXBvbmVudFR5cGU9ZS5jb21wb25lbnRUeXBlKTtsZXQgcj1uZXcgbGUodCk7aWYoci5uYW1lPUEubmFtZSxyLm9yaWdpbj1BcnJheS5mcm9tKEEub3JpZ2luKSxyLnNwYWNpbmc9QXJyYXkuZnJvbShBLnNwYWNpbmcpLHIuZGlyZWN0aW9uPUEuZGlyZWN0aW9uLnNsaWNlKCksci5zaXplPUFycmF5LmZyb20oQS5zaXplKSxyLm1ldGFkYXRhPW5ldyBNYXAoSlNPTi5wYXJzZShKU09OLnN0cmluZ2lmeShBcnJheS5mcm9tKEEubWV0YWRhdGEpKSkpLEEuZGF0YSE9PW51bGwpaWYodHlwZW9mIGU8InUiJiZ0eXBlb2YgZS5jb21wb25lbnRUeXBlPCJ1IiYmZS5jb21wb25lbnRUeXBlIT09QS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSlzd2l0Y2goQS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSl7Y2FzZSBRLlVJbnQ4OmNhc2UgUS5JbnQ4OmNhc2UgUS5VSW50MTY6Y2FzZSBRLkludDE2OmNhc2UgUS5VSW50MzI6Y2FzZSBRLkludDMyOmNhc2UgRC5GbG9hdDMyOmNhc2UgRC5GbG9hdDY0OnN3aXRjaChyLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKXtjYXNlIFEuVUludDg6ci5kYXRhPW5ldyBVaW50OEFycmF5KEEuZGF0YSk7YnJlYWs7Y2FzZSBRLkludDg6ci5kYXRhPW5ldyBJbnQ4QXJyYXkoQS5kYXRhKTticmVhaztjYXNlIFEuVUludDE2OnIuZGF0YT1uZXcgVWludDE2QXJyYXkoQS5kYXRhKTticmVhaztjYXNlIFEuSW50MTY6ci5kYXRhPW5ldyBJbnQxNkFycmF5KEEuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQzMjpyLmRhdGE9bmV3IFVpbnQzMkFycmF5KEEuZGF0YSk7YnJlYWs7Y2FzZSBRLkludDMyOnIuZGF0YT1uZXcgSW50MzJBcnJheShBLmRhdGEpO2JyZWFrO2Nhc2UgRC5GbG9hdDMyOnIuZGF0YT1uZXcgRmxvYXQzMkFycmF5KEEuZGF0YSk7YnJlYWs7Y2FzZSBELkZsb2F0NjQ6ci5kYXRhPW5ldyBGbG9hdDY0QXJyYXkoQS5kYXRhKTticmVhaztjYXNlIFEuVUludDY0OnIuZGF0YT1uZXcgQmlnVWludDY0QXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09QmlnSW50LmFzSW50Tig2NCxCaWdJbnQoQS5kYXRhW25dKSk7YnJlYWs7Y2FzZSBRLkludDY0OnIuZGF0YT1uZXcgQmlnSW50NjRBcnJheShBLmRhdGEubGVuZ3RoKTtmb3IobGV0IG49MDtuPHIuZGF0YS5sZW5ndGg7bisrKXIuZGF0YVtuXT1CaWdJbnQuYXNVaW50Tig2NCxCaWdJbnQoQS5kYXRhW25dKSk7YnJlYWt9YnJlYWs7Y2FzZSBRLlVJbnQ2NDpjYXNlIFEuSW50NjQ6c3dpdGNoKHIuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpe2Nhc2UgUS5VSW50ODpyLmRhdGE9bmV3IFVpbnQ4QXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09TnVtYmVyKEEuZGF0YVtuXSk7YnJlYWs7Y2FzZSBRLkludDg6ci5kYXRhPW5ldyBJbnQ4QXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09TnVtYmVyKEEuZGF0YVtuXSk7YnJlYWs7Y2FzZSBRLlVJbnQxNjpyLmRhdGE9bmV3IFVpbnQxNkFycmF5KEEuZGF0YS5sZW5ndGgpO2ZvcihsZXQgbj0wO248ci5kYXRhLmxlbmd0aDtuKyspci5kYXRhW25dPU51bWJlcihBLmRhdGFbbl0pO2JyZWFrO2Nhc2UgUS5JbnQxNjpyLmRhdGE9bmV3IEludDE2QXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09TnVtYmVyKEEuZGF0YVtuXSk7YnJlYWs7Y2FzZSBRLlVJbnQzMjpyLmRhdGE9bmV3IFVpbnQzMkFycmF5KEEuZGF0YS5sZW5ndGgpO2ZvcihsZXQgbj0wO248ci5kYXRhLmxlbmd0aDtuKyspci5kYXRhW25dPU51bWJlcihBLmRhdGFbbl0pO2JyZWFrO2Nhc2UgUS5JbnQzMjpyLmRhdGE9bmV3IEludDMyQXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09TnVtYmVyKEEuZGF0YVtuXSk7YnJlYWs7Y2FzZSBELkZsb2F0MzI6ci5kYXRhPW5ldyBGbG9hdDMyQXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09TnVtYmVyKEEuZGF0YVtuXSk7YnJlYWs7Y2FzZSBELkZsb2F0NjQ6ci5kYXRhPW5ldyBGbG9hdDY0QXJyYXkoQS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBuPTA7bjxyLmRhdGEubGVuZ3RoO24rKylyLmRhdGFbbl09TnVtYmVyKEEuZGF0YVtuXSk7YnJlYWs7Y2FzZSBRLlVJbnQ2NDpyLmRhdGE9bmV3IEJpZ1VpbnQ2NEFycmF5KEEuZGF0YSk7YnJlYWs7Y2FzZSBRLkludDY0OnIuZGF0YT1uZXcgQmlnSW50NjRBcnJheShBLmRhdGEpO2JyZWFrfWJyZWFrfWVsc2V7bGV0IG49QS5kYXRhLmNvbnN0cnVjdG9yO3IuZGF0YT1uZXcgbihBLmRhdGEubGVuZ3RoKSxyLmRhdGEhPW51bGwmJnIuZGF0YS5zZXQoQS5kYXRhLDApfXJldHVybiByfXZhciBvQT1SdDt2YXIgTnQ9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIE90KEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCB0PTA7dDxBLmxlbmd0aDt0Kyspe2xldCByPUd0KEFbdF0pO3IhPT1udWxsJiZlLnB1c2gocil9cmV0dXJuIGV9ZnVuY3Rpb24gR3QoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgZT1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD9lPUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKGU9QSksTnQmJmUgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmV9dmFyIENlPU90O2Z1bmN0aW9uIFooQSxlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShlLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzpUdH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6TkF9PU9iamVjdCxJQT0oQT0+ZT0+e2xldCB0PVR0LmNhbGwoZSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxHPUE9PihBPUEudG9Mb3dlckNhc2UoKSxlPT5JQShlKT09PUEpLGdBPUE9PmU9PnR5cGVvZiBlPT09QSx7aXNBcnJheTpxfT1BcnJheSxYPWdBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiBMdChBKXtyZXR1cm4gQSE9PW51bGwmJiFYKEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIVgoQS5jb25zdHJ1Y3RvcikmJk8oQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIGZlPUcoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24geHQoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZmZShBLmJ1ZmZlciksZX12YXIgUHQ9Z0EoInN0cmluZyIpLE89Z0EoImZ1bmN0aW9uIiksRWU9Z0EoIm51bWJlciIpLGxBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsTXQ9QT0+QT09PSEwfHxBPT09ITEsc0E9QT0+e2lmKElBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9TkEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sSnQ9RygiRGF0ZSIpLEh0PUcoIkZpbGUiKSxZdD1HKCJCbG9iIikscXQ9RygiRmlsZUxpc3QiKSxLdD1BPT5sQShBKSYmTyhBLnBpcGUpLHZ0PUE9PntsZXQgZTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxPKEEuYXBwZW5kKSYmKChlPUlBKEEpKT09PSJmb3JtZGF0YSJ8fGU9PT0ib2JqZWN0IiYmTyhBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxqdD1HKCJVUkxTZWFyY2hQYXJhbXMiKSxXdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xzXHVGRUZGXHhBMF0rfFtcc1x1RkVGRlx4QTBdKyQvZywiIik7ZnVuY3Rpb24gJChBLGUse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCByLG47aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLHEoQSkpZm9yKHI9MCxuPUEubGVuZ3RoO3I8bjtyKyspZS5jYWxsKG51bGwsQVtyXSxyLEEpO2Vsc2V7bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxhPWkubGVuZ3RoLGc7Zm9yKHI9MDtyPGE7cisrKWc9aVtyXSxlLmNhbGwobnVsbCxBW2ddLGcsQSl9fWZ1bmN0aW9uIFFlKEEsZSl7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSkscj10Lmxlbmd0aCxuO2Zvcig7ci0tID4wOylpZihuPXRbcl0sZT09PW4udG9Mb3dlckNhc2UoKSlyZXR1cm4gbjtyZXR1cm4gbnVsbH12YXIgdWU9KCgpPT50eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsKSgpLGRlPUE9PiFYKEEpJiZBIT09dWU7ZnVuY3Rpb24gUkEoKXtsZXR7Y2FzZWxlc3M6QX09ZGUodGhpcykmJnRoaXN8fHt9LGU9e30sdD0ocixuKT0+e2xldCBpPUEmJlFlKGUsbil8fG47c0EoZVtpXSkmJnNBKHIpP2VbaV09UkEoZVtpXSxyKTpzQShyKT9lW2ldPVJBKHt9LHIpOnEocik/ZVtpXT1yLnNsaWNlKCk6ZVtpXT1yfTtmb3IobGV0IHI9MCxuPWFyZ3VtZW50cy5sZW5ndGg7cjxuO3IrKylhcmd1bWVudHNbcl0mJiQoYXJndW1lbnRzW3JdLHQpO3JldHVybiBlfXZhciBfdD0oQSxlLHQse2FsbE93bktleXM6cn09e30pPT4oJChlLChuLGkpPT57dCYmTyhuKT9BW2ldPVoobix0KTpBW2ldPW59LHthbGxPd25LZXlzOnJ9KSxBKSx6dD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLFZ0PShBLGUsdCxyKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZS5wcm90b3R5cGUsciksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTplLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LFp0PShBLGUsdCxyKT0+e2xldCBuLGksYSxnPXt9O2lmKGU9ZXx8e30sQT09bnVsbClyZXR1cm4gZTtkb3tmb3Iobj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxpPW4ubGVuZ3RoO2ktLSA+MDspYT1uW2ldLCghcnx8cihhLEEsZSkpJiYhZ1thXSYmKGVbYV09QVthXSxnW2FdPSEwKTtBPXQhPT0hMSYmTkEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsZSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIGV9LFh0PShBLGUsdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1lLmxlbmd0aDtsZXQgcj1BLmluZGV4T2YoZSx0KTtyZXR1cm4gciE9PS0xJiZyPT09dH0sJHQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKHEoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIUVlKGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxBcj0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmTkEoVWludDhBcnJheSkpLGVyPShBLGUpPT57bGV0IHI9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxuO2Zvcig7KG49ci5uZXh0KCkpJiYhbi5kb25lOyl7bGV0IGk9bi52YWx1ZTtlLmNhbGwoQSxpWzBdLGlbMV0pfX0sdHI9KEEsZSk9PntsZXQgdCxyPVtdO2Zvcig7KHQ9QS5leGVjKGUpKSE9PW51bGw7KXIucHVzaCh0KTtyZXR1cm4gcn0scnI9RygiSFRNTEZvcm1FbGVtZW50IiksbnI9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xzXShbYS16XGRdKShcdyopL2csZnVuY3Rpb24odCxyLG4pe3JldHVybiByLnRvVXBwZXJDYXNlKCkrbn0pLGNlPSgoe2hhc093blByb3BlcnR5OkF9KT0+KGUsdCk9PkEuY2FsbChlLHQpKShPYmplY3QucHJvdG90eXBlKSxpcj1HKCJSZWdFeHAiKSxwZT0oQSxlKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLHI9e307JCh0LChuLGkpPT57bGV0IGE7KGE9ZShuLGksQSkpIT09ITEmJihyW2ldPWF8fG4pfSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQSxyKX0sYXI9QT0+e3BlKEEsKGUsdCk9PntpZihPKEEpJiZbImFyZ3VtZW50cyIsImNhbGxlciIsImNhbGxlZSJdLmluZGV4T2YodCkhPT0tMSlyZXR1cm4hMTtsZXQgcj1BW3RdO2lmKE8ocikpe2lmKGUuZW51bWVyYWJsZT0hMSwid3JpdGFibGUiaW4gZSl7ZS53cml0YWJsZT0hMTtyZXR1cm59ZS5zZXR8fChlLnNldD0oKT0+e3Rocm93IEVycm9yKCJDYW4gbm90IHJld3JpdGUgcmVhZC1vbmx5IG1ldGhvZCAnIit0KyInIil9KX19KX0sb3I9KEEsZSk9PntsZXQgdD17fSxyPW49PntuLmZvckVhY2goaT0+e3RbaV09ITB9KX07cmV0dXJuIHEoQSk/cihBKTpyKFN0cmluZyhBKS5zcGxpdChlKSksdH0sc3I9KCk9Pnt9LElyPShBLGUpPT4oQT0rQSxOdW1iZXIuaXNGaW5pdGUoQSk/QTplKSxVQT0iYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXoiLEJlPSIwMTIzNDU2Nzg5IixtZT17RElHSVQ6QmUsQUxQSEE6VUEsQUxQSEFfRElHSVQ6VUErVUEudG9VcHBlckNhc2UoKStCZX0sZ3I9KEE9MTYsZT1tZS5BTFBIQV9ESUdJVCk9PntsZXQgdD0iIix7bGVuZ3RoOnJ9PWU7Zm9yKDtBLS07KXQrPWVbTWF0aC5yYW5kb20oKSpyfDBdO3JldHVybiB0fTtmdW5jdGlvbiBscihBKXtyZXR1cm4hIShBJiZPKEEuYXBwZW5kKSYmQVtTeW1ib2wudG9TdHJpbmdUYWddPT09IkZvcm1EYXRhIiYmQVtTeW1ib2wuaXRlcmF0b3JdKX12YXIgQ3I9QT0+e2xldCBlPW5ldyBBcnJheSgxMCksdD0ocixuKT0+e2lmKGxBKHIpKXtpZihlLmluZGV4T2Yocik+PTApcmV0dXJuO2lmKCEoInRvSlNPTiJpbiByKSl7ZVtuXT1yO2xldCBpPXEocik/W106e307cmV0dXJuICQociwoYSxnKT0+e2xldCBmPXQoYSxuKzEpOyFYKGYpJiYoaVtnXT1mKX0pLGVbbl09dm9pZCAwLGl9fXJldHVybiByfTtyZXR1cm4gdChBLDApfSxjcj1HKCJBc3luY0Z1bmN0aW9uIiksQnI9QT0+QSYmKGxBKEEpfHxPKEEpKSYmTyhBLnRoZW4pJiZPKEEuY2F0Y2gpLHM9e2lzQXJyYXk6cSxpc0FycmF5QnVmZmVyOmZlLGlzQnVmZmVyOkx0LGlzRm9ybURhdGE6dnQsaXNBcnJheUJ1ZmZlclZpZXc6eHQsaXNTdHJpbmc6UHQsaXNOdW1iZXI6RWUsaXNCb29sZWFuOk10LGlzT2JqZWN0OmxBLGlzUGxhaW5PYmplY3Q6c0EsaXNVbmRlZmluZWQ6WCxpc0RhdGU6SnQsaXNGaWxlOkh0LGlzQmxvYjpZdCxpc1JlZ0V4cDppcixpc0Z1bmN0aW9uOk8saXNTdHJlYW06S3QsaXNVUkxTZWFyY2hQYXJhbXM6anQsaXNUeXBlZEFycmF5OkFyLGlzRmlsZUxpc3Q6cXQsZm9yRWFjaDokLG1lcmdlOlJBLGV4dGVuZDpfdCx0cmltOld0LHN0cmlwQk9NOnp0LGluaGVyaXRzOlZ0LHRvRmxhdE9iamVjdDpadCxraW5kT2Y6SUEsa2luZE9mVGVzdDpHLGVuZHNXaXRoOlh0LHRvQXJyYXk6JHQsZm9yRWFjaEVudHJ5OmVyLG1hdGNoQWxsOnRyLGlzSFRNTEZvcm06cnIsaGFzT3duUHJvcGVydHk6Y2UsaGFzT3duUHJvcDpjZSxyZWR1Y2VEZXNjcmlwdG9yczpwZSxmcmVlemVNZXRob2RzOmFyLHRvT2JqZWN0U2V0Om9yLHRvQ2FtZWxDYXNlOm5yLG5vb3A6c3IsdG9GaW5pdGVOdW1iZXI6SXIsZmluZEtleTpRZSxnbG9iYWw6dWUsaXNDb250ZXh0RGVmaW5lZDpkZSxBTFBIQUJFVDptZSxnZW5lcmF0ZVN0cmluZzpncixpc1NwZWNDb21wbGlhbnRGb3JtOmxyLHRvSlNPTk9iamVjdDpDcixpc0FzeW5jRm46Y3IsaXNUaGVuYWJsZTpCcn07ZnVuY3Rpb24gSyhBLGUsdCxyLG4pe0Vycm9yLmNhbGwodGhpcyksRXJyb3IuY2FwdHVyZVN0YWNrVHJhY2U/RXJyb3IuY2FwdHVyZVN0YWNrVHJhY2UodGhpcyx0aGlzLmNvbnN0cnVjdG9yKTp0aGlzLnN0YWNrPW5ldyBFcnJvcigpLnN0YWNrLHRoaXMubWVzc2FnZT1BLHRoaXMubmFtZT0iQXhpb3NFcnJvciIsZSYmKHRoaXMuY29kZT1lKSx0JiYodGhpcy5jb25maWc9dCksciYmKHRoaXMucmVxdWVzdD1yKSxuJiYodGhpcy5yZXNwb25zZT1uKX1zLmluaGVyaXRzKEssRXJyb3Ise3RvSlNPTjpmdW5jdGlvbigpe3JldHVybnttZXNzYWdlOnRoaXMubWVzc2FnZSxuYW1lOnRoaXMubmFtZSxkZXNjcmlwdGlvbjp0aGlzLmRlc2NyaXB0aW9uLG51bWJlcjp0aGlzLm51bWJlcixmaWxlTmFtZTp0aGlzLmZpbGVOYW1lLGxpbmVOdW1iZXI6dGhpcy5saW5lTnVtYmVyLGNvbHVtbk51bWJlcjp0aGlzLmNvbHVtbk51bWJlcixzdGFjazp0aGlzLnN0YWNrLGNvbmZpZzpzLnRvSlNPTk9iamVjdCh0aGlzLmNvbmZpZyksY29kZTp0aGlzLmNvZGUsc3RhdHVzOnRoaXMucmVzcG9uc2UmJnRoaXMucmVzcG9uc2Uuc3RhdHVzP3RoaXMucmVzcG9uc2Uuc3RhdHVzOm51bGx9fX0pO3ZhciBoZT1LLnByb3RvdHlwZSx5ZT17fTtbIkVSUl9CQURfT1BUSU9OX1ZBTFVFIiwiRVJSX0JBRF9PUFRJT04iLCJFQ09OTkFCT1JURUQiLCJFVElNRURPVVQiLCJFUlJfTkVUV09SSyIsIkVSUl9GUl9UT09fTUFOWV9SRURJUkVDVFMiLCJFUlJfREVQUkVDQVRFRCIsIkVSUl9CQURfUkVTUE9OU0UiLCJFUlJfQkFEX1JFUVVFU1QiLCJFUlJfQ0FOQ0VMRUQiLCJFUlJfTk9UX1NVUFBPUlQiLCJFUlJfSU5WQUxJRF9VUkwiXS5mb3JFYWNoKEE9Pnt5ZVtBXT17dmFsdWU6QX19KTtPYmplY3QuZGVmaW5lUHJvcGVydGllcyhLLHllKTtPYmplY3QuZGVmaW5lUHJvcGVydHkoaGUsImlzQXhpb3NFcnJvciIse3ZhbHVlOiEwfSk7Sy5mcm9tPShBLGUsdCxyLG4saSk9PntsZXQgYT1PYmplY3QuY3JlYXRlKGhlKTtyZXR1cm4gcy50b0ZsYXRPYmplY3QoQSxhLGZ1bmN0aW9uKGYpe3JldHVybiBmIT09RXJyb3IucHJvdG90eXBlfSxnPT5nIT09ImlzQXhpb3NFcnJvciIpLEsuY2FsbChhLEEubWVzc2FnZSxlLHQscixuKSxhLmNhdXNlPUEsYS5uYW1lPUEubmFtZSxpJiZPYmplY3QuYXNzaWduKGEsaSksYX07dmFyIHU9Szt2YXIgQ0E9bnVsbDtmdW5jdGlvbiBPQShBKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KEEpfHxzLmlzQXJyYXkoQSl9ZnVuY3Rpb24gRGUoQSl7cmV0dXJuIHMuZW5kc1dpdGgoQSwiW10iKT9BLnNsaWNlKDAsLTIpOkF9ZnVuY3Rpb24gd2UoQSxlLHQpe3JldHVybiBBP0EuY29uY2F0KGUpLm1hcChmdW5jdGlvbihuLGkpe3JldHVybiBuPURlKG4pLCF0JiZpPyJbIituKyJdIjpufSkuam9pbih0PyIuIjoiIik6ZX1mdW5jdGlvbiBmcihBKXtyZXR1cm4gcy5pc0FycmF5KEEpJiYhQS5zb21lKE9BKX12YXIgRXI9cy50b0ZsYXRPYmplY3Qocyx7fSxudWxsLGZ1bmN0aW9uKGUpe3JldHVybi9eaXNbQS1aXS8udGVzdChlKX0pO2Z1bmN0aW9uIFFyKEEsZSx0KXtpZighcy5pc09iamVjdChBKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJ0YXJnZXQgbXVzdCBiZSBhbiBvYmplY3QiKTtlPWV8fG5ldyhDQXx8Rm9ybURhdGEpLHQ9cy50b0ZsYXRPYmplY3QodCx7bWV0YVRva2VuczohMCxkb3RzOiExLGluZGV4ZXM6ITF9LCExLGZ1bmN0aW9uKEUsbSl7cmV0dXJuIXMuaXNVbmRlZmluZWQobVtFXSl9KTtsZXQgcj10Lm1ldGFUb2tlbnMsbj10LnZpc2l0b3J8fG8saT10LmRvdHMsYT10LmluZGV4ZXMsZj0odC5CbG9ifHx0eXBlb2YgQmxvYjwidSImJkJsb2IpJiZzLmlzU3BlY0NvbXBsaWFudEZvcm0oZSk7aWYoIXMuaXNGdW5jdGlvbihuKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJ2aXNpdG9yIG11c3QgYmUgYSBmdW5jdGlvbiIpO2Z1bmN0aW9uIEkobCl7aWYobD09PW51bGwpcmV0dXJuIiI7aWYocy5pc0RhdGUobCkpcmV0dXJuIGwudG9JU09TdHJpbmcoKTtpZighZiYmcy5pc0Jsb2IobCkpdGhyb3cgbmV3IHUoIkJsb2IgaXMgbm90IHN1cHBvcnRlZC4gVXNlIGEgQnVmZmVyIGluc3RlYWQuIik7cmV0dXJuIHMuaXNBcnJheUJ1ZmZlcihsKXx8cy5pc1R5cGVkQXJyYXkobCk/ZiYmdHlwZW9mIEJsb2I9PSJmdW5jdGlvbiI/bmV3IEJsb2IoW2xdKTpCdWZmZXIuZnJvbShsKTpsfWZ1bmN0aW9uIG8obCxFLG0pe2xldCBoPWw7aWYobCYmIW0mJnR5cGVvZiBsPT0ib2JqZWN0Iil7aWYocy5lbmRzV2l0aChFLCJ7fSIpKUU9cj9FOkUuc2xpY2UoMCwtMiksbD1KU09OLnN0cmluZ2lmeShsKTtlbHNlIGlmKHMuaXNBcnJheShsKSYmZnIobCl8fChzLmlzRmlsZUxpc3QobCl8fHMuZW5kc1dpdGgoRSwiW10iKSkmJihoPXMudG9BcnJheShsKSkpcmV0dXJuIEU9RGUoRSksaC5mb3JFYWNoKGZ1bmN0aW9uKHcsU0EpeyEocy5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZlLmFwcGVuZChhPT09ITA/d2UoW0VdLFNBLGkpOmE9PT1udWxsP0U6RSsiW10iLEkodykpfSksITF9cmV0dXJuIE9BKGwpPyEwOihlLmFwcGVuZCh3ZShtLEUsaSksSShsKSksITEpfWxldCBCPVtdLGM9T2JqZWN0LmFzc2lnbihFcix7ZGVmYXVsdFZpc2l0b3I6byxjb252ZXJ0VmFsdWU6SSxpc1Zpc2l0YWJsZTpPQX0pO2Z1bmN0aW9uIEMobCxFKXtpZighcy5pc1VuZGVmaW5lZChsKSl7aWYoQi5pbmRleE9mKGwpIT09LTEpdGhyb3cgRXJyb3IoIkNpcmN1bGFyIHJlZmVyZW5jZSBkZXRlY3RlZCBpbiAiK0Uuam9pbigiLiIpKTtCLnB1c2gobCkscy5mb3JFYWNoKGwsZnVuY3Rpb24oaCxwKXsoIShzLmlzVW5kZWZpbmVkKGgpfHxoPT09bnVsbCkmJm4uY2FsbChlLGgscy5pc1N0cmluZyhwKT9wLnRyaW0oKTpwLEUsYykpPT09ITAmJkMoaCxFP0UuY29uY2F0KHApOltwXSl9KSxCLnBvcCgpfX1pZighcy5pc09iamVjdChBKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJkYXRhIG11c3QgYmUgYW4gb2JqZWN0Iik7cmV0dXJuIEMoQSksZX12YXIgTD1RcjtmdW5jdGlvbiBiZShBKXtsZXQgZT17IiEiOiIlMjEiLCInIjoiJTI3IiwiKCI6IiUyOCIsIikiOiIlMjkiLCJ+IjoiJTdFIiwiJTIwIjoiKyIsIiUwMCI6IlwwIn07cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC9bIScoKX5dfCUyMHwlMDAvZyxmdW5jdGlvbihyKXtyZXR1cm4gZVtyXX0pfWZ1bmN0aW9uIFNlKEEsZSl7dGhpcy5fcGFpcnM9W10sQSYmTChBLHRoaXMsZSl9dmFyIEZlPVNlLnByb3RvdHlwZTtGZS5hcHBlbmQ9ZnVuY3Rpb24oZSx0KXt0aGlzLl9wYWlycy5wdXNoKFtlLHRdKX07RmUudG9TdHJpbmc9ZnVuY3Rpb24oZSl7bGV0IHQ9ZT9mdW5jdGlvbihyKXtyZXR1cm4gZS5jYWxsKHRoaXMscixiZSl9OmJlO3JldHVybiB0aGlzLl9wYWlycy5tYXAoZnVuY3Rpb24obil7cmV0dXJuIHQoblswXSkrIj0iK3QoblsxXSl9LCIiKS5qb2luKCImIil9O3ZhciBjQT1TZTtmdW5jdGlvbiB1cihBKXtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoLyUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNC9nLCIkIikucmVwbGFjZSgvJTJDL2dpLCIsIikucmVwbGFjZSgvJTIwL2csIisiKS5yZXBsYWNlKC8lNUIvZ2ksIlsiKS5yZXBsYWNlKC8lNUQvZ2ksIl0iKX1mdW5jdGlvbiBBQShBLGUsdCl7aWYoIWUpcmV0dXJuIEE7bGV0IHI9dCYmdC5lbmNvZGV8fHVyLG49dCYmdC5zZXJpYWxpemUsaTtpZihuP2k9bihlLHQpOmk9cy5pc1VSTFNlYXJjaFBhcmFtcyhlKT9lLnRvU3RyaW5nKCk6bmV3IGNBKGUsdCkudG9TdHJpbmcociksaSl7bGV0IGE9QS5pbmRleE9mKCIjIik7YSE9PS0xJiYoQT1BLnNsaWNlKDAsYSkpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIEdBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LHIpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6cj9yLnN5bmNocm9ub3VzOiExLHJ1bldoZW46cj9yLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihyKXtyIT09bnVsbCYmZShyKX0pfX0sVEE9R0E7dmFyIEJBPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIga2U9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOmNBO3ZhciBVZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIFJlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIE5lPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOmtlLEZvcm1EYXRhOlVlLEJsb2I6UmV9LHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTt2YXIgTEE9e307bXQoTEEse2hhc0Jyb3dzZXJFbnY6KCk9Pk9lLGhhc1N0YW5kYXJkQnJvd3NlckVudjooKT0+ZHIsaGFzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52OigpPT5wcn0pO3ZhciBPZT10eXBlb2Ygd2luZG93PCJ1IiYmdHlwZW9mIGRvY3VtZW50PCJ1Iixkcj0oQT0+T2UmJlsiUmVhY3ROYXRpdmUiLCJOYXRpdmVTY3JpcHQiLCJOUyJdLmluZGV4T2YoQSk8MCkodHlwZW9mIG5hdmlnYXRvcjwidSImJm5hdmlnYXRvci5wcm9kdWN0KSxwcj0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKTt2YXIgRj17Li4uTEEsLi4uTmV9O2Z1bmN0aW9uIHhBKEEsZSl7cmV0dXJuIEwoQSxuZXcgRi5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKHQscixuLGkpe3JldHVybiBGLmlzTm9kZSYmcy5pc0J1ZmZlcih0KT8odGhpcy5hcHBlbmQocix0LnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOmkuZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sZSkpfWZ1bmN0aW9uIG1yKEEpe3JldHVybiBzLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxBKS5tYXAoZT0+ZVswXT09PSJbXSI/IiI6ZVsxXXx8ZVswXSl9ZnVuY3Rpb24gaHIoQSl7bGV0IGU9e30sdD1PYmplY3Qua2V5cyhBKSxyLG49dC5sZW5ndGgsaTtmb3Iocj0wO3I8bjtyKyspaT10W3JdLGVbaV09QVtpXTtyZXR1cm4gZX1mdW5jdGlvbiB5cihBKXtmdW5jdGlvbiBlKHQscixuLGkpe2xldCBhPXRbaSsrXSxnPU51bWJlci5pc0Zpbml0ZSgrYSksZj1pPj10Lmxlbmd0aDtyZXR1cm4gYT0hYSYmcy5pc0FycmF5KG4pP24ubGVuZ3RoOmEsZj8ocy5oYXNPd25Qcm9wKG4sYSk/blthXT1bblthXSxyXTpuW2FdPXIsIWcpOigoIW5bYV18fCFzLmlzT2JqZWN0KG5bYV0pKSYmKG5bYV09W10pLGUodCxyLG5bYV0saSkmJnMuaXNBcnJheShuW2FdKSYmKG5bYV09aHIoblthXSkpLCFnKX1pZihzLmlzRm9ybURhdGEoQSkmJnMuaXNGdW5jdGlvbihBLmVudHJpZXMpKXtsZXQgdD17fTtyZXR1cm4gcy5mb3JFYWNoRW50cnkoQSwocixuKT0+e2UobXIociksbix0LDApfSksdH1yZXR1cm4gbnVsbH12YXIgZkE9eXI7ZnVuY3Rpb24gd3IoQSxlLHQpe2lmKHMuaXNTdHJpbmcoQSkpdHJ5e3JldHVybihlfHxKU09OLnBhcnNlKShBKSxzLnRyaW0oQSl9Y2F0Y2gocil7aWYoci5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyByfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoQSl9dmFyIFBBPXt0cmFuc2l0aW9uYWw6QkEsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihlLHQpe2xldCByPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIsbj1yLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxpPXMuaXNPYmplY3QoZSk7aWYoaSYmcy5pc0hUTUxGb3JtKGUpJiYoZT1uZXcgRm9ybURhdGEoZSkpLHMuaXNGb3JtRGF0YShlKSlyZXR1cm4gbiYmbj9KU09OLnN0cmluZ2lmeShmQShlKSk6ZTtpZihzLmlzQXJyYXlCdWZmZXIoZSl8fHMuaXNCdWZmZXIoZSl8fHMuaXNTdHJlYW0oZSl8fHMuaXNGaWxlKGUpfHxzLmlzQmxvYihlKSlyZXR1cm4gZTtpZihzLmlzQXJyYXlCdWZmZXJWaWV3KGUpKXJldHVybiBlLmJ1ZmZlcjtpZihzLmlzVVJMU2VhcmNoUGFyYW1zKGUpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLGUudG9TdHJpbmcoKTtsZXQgZztpZihpKXtpZihyLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiB4QShlLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKGc9cy5pc0ZpbGVMaXN0KGUpKXx8ci5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBmPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gTChnP3siZmlsZXNbXSI6ZX06ZSxmJiZuZXcgZix0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIGl8fG4/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSx3cihlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8UEEudHJhbnNpdGlvbmFsLHI9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxuPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKGUmJnMuaXNTdHJpbmcoZSkmJihyJiYhdGhpcy5yZXNwb25zZVR5cGV8fG4pKXtsZXQgYT0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZuO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChnKXtpZihhKXRocm93IGcubmFtZT09PSJTeW50YXhFcnJvciI/dS5mcm9tKGcsdS5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpnfX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6Ri5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6Ri5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07cy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLEE9PntQQS5oZWFkZXJzW0FdPXt9fSk7dmFyIHY9UEE7dmFyIERyPXMudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksR2U9QT0+e2xldCBlPXt9LHQscixuO3JldHVybiBBJiZBLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihhKXtuPWEuaW5kZXhPZigiOiIpLHQ9YS5zdWJzdHJpbmcoMCxuKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPWEuc3Vic3RyaW5nKG4rMSkudHJpbSgpLCEoIXR8fGVbdF0mJkRyW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2gocik6ZVt0XT1bcl06ZVt0XT1lW3RdP2VbdF0rIiwgIityOnIpfSksZX07dmFyIFRlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBFQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6cy5pc0FycmF5KEEpP0EubWFwKEVBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gYnIoQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9dC5leGVjKEEpOyllW3JbMV1dPXJbMl07cmV0dXJuIGV9dmFyIFNyPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIE1BKEEsZSx0LHIsbil7aWYocy5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyxlLHQpO2lmKG4mJihlPXQpLCEhcy5pc1N0cmluZyhlKSl7aWYocy5pc1N0cmluZyhyKSlyZXR1cm4gZS5pbmRleE9mKHIpIT09LTE7aWYocy5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KGUpfX1mdW5jdGlvbiBGcihBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLChlLHQscik9PnQudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBrcihBLGUpe2xldCB0PXMudG9DYW1lbENhc2UoIiAiK2UpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KEEscit0LHt2YWx1ZTpmdW5jdGlvbihuLGksYSl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLGUsbixpLGEpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBqPWNsYXNze2NvbnN0cnVjdG9yKGUpe2UmJnRoaXMuc2V0KGUpfXNldChlLHQscil7bGV0IG49dGhpcztmdW5jdGlvbiBpKGcsZixJKXtsZXQgbz1lQShmKTtpZighbyl0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IEI9cy5maW5kS2V5KG4sbyk7KCFCfHxuW0JdPT09dm9pZCAwfHxJPT09ITB8fEk9PT12b2lkIDAmJm5bQl0hPT0hMSkmJihuW0J8fGZdPUVBKGcpKX1sZXQgYT0oZyxmKT0+cy5mb3JFYWNoKGcsKEksbyk9PmkoSSxvLGYpKTtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KGUpfHxlIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9hKGUsdCk6cy5pc1N0cmluZyhlKSYmKGU9ZS50cmltKCkpJiYhU3IoZSk/YShHZShlKSx0KTplIT1udWxsJiZpKHQsZSxyKSx0aGlzfWdldChlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IHI9cy5maW5kS2V5KHRoaXMsZSk7aWYocil7bGV0IG49dGhpc1tyXTtpZighdClyZXR1cm4gbjtpZih0PT09ITApcmV0dXJuIGJyKG4pO2lmKHMuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsbixyKTtpZihzLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMobik7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IHI9cy5maW5kS2V5KHRoaXMsZSk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCF0fHxNQSh0aGlzLHRoaXNbcl0scix0KSkpfXJldHVybiExfWRlbGV0ZShlLHQpe2xldCByPXRoaXMsbj0hMTtmdW5jdGlvbiBpKGEpe2lmKGE9ZUEoYSksYSl7bGV0IGc9cy5maW5kS2V5KHIsYSk7ZyYmKCF0fHxNQShyLHJbZ10sZyx0KSkmJihkZWxldGUgcltnXSxuPSEwKX19cmV0dXJuIHMuaXNBcnJheShlKT9lLmZvckVhY2goaSk6aShlKSxufWNsZWFyKGUpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLHI9dC5sZW5ndGgsbj0hMTtmb3IoO3ItLTspe2xldCBpPXRbcl07KCFlfHxNQSh0aGlzLHRoaXNbaV0saSxlLCEwKSkmJihkZWxldGUgdGhpc1tpXSxuPSEwKX1yZXR1cm4gbn1ub3JtYWxpemUoZSl7bGV0IHQ9dGhpcyxyPXt9O3JldHVybiBzLmZvckVhY2godGhpcywobixpKT0+e2xldCBhPXMuZmluZEtleShyLGkpO2lmKGEpe3RbYV09RUEobiksZGVsZXRlIHRbaV07cmV0dXJufWxldCBnPWU/RnIoaSk6U3RyaW5nKGkpLnRyaW0oKTtnIT09aSYmZGVsZXRlIHRbaV0sdFtnXT1FQShuKSxyW2ddPSEwfSksdGhpc31jb25jYXQoLi4uZSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uZSl9dG9KU09OKGUpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChyLG4pPT57ciE9bnVsbCYmciE9PSExJiYodFtuXT1lJiZzLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbZSx0XSk9PmUrIjogIit0KS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShlKXtyZXR1cm4gZSBpbnN0YW5jZW9mIHRoaXM/ZTpuZXcgdGhpcyhlKX1zdGF0aWMgY29uY2F0KGUsLi4udCl7bGV0IHI9bmV3IHRoaXMoZSk7cmV0dXJuIHQuZm9yRWFjaChuPT5yLnNldChuKSkscn1zdGF0aWMgYWNjZXNzb3IoZSl7bGV0IHI9KHRoaXNbVGVdPXRoaXNbVGVdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsbj10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBpKGEpe2xldCBnPWVBKGEpO3JbZ118fChrcihuLGEpLHJbZ109ITApfXJldHVybiBzLmlzQXJyYXkoZSk/ZS5mb3JFYWNoKGkpOmkoZSksdGhpc319O2ouYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO3MucmVkdWNlRGVzY3JpcHRvcnMoai5wcm90b3R5cGUsKHt2YWx1ZTpBfSxlKT0+e2xldCB0PWVbMF0udG9VcHBlckNhc2UoKStlLnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PkEsc2V0KHIpe3RoaXNbdF09cn19fSk7cy5mcmVlemVNZXRob2RzKGopO3ZhciBrPWo7ZnVuY3Rpb24gdEEoQSxlKXtsZXQgdD10aGlzfHx2LHI9ZXx8dCxuPWsuZnJvbShyLmhlYWRlcnMpLGk9ci5kYXRhO3JldHVybiBzLmZvckVhY2goQSxmdW5jdGlvbihnKXtpPWcuY2FsbCh0LGksbi5ub3JtYWxpemUoKSxlP2Uuc3RhdHVzOnZvaWQgMCl9KSxuLm5vcm1hbGl6ZSgpLGl9ZnVuY3Rpb24gckEoQSl7cmV0dXJuISEoQSYmQS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBMZShBLGUsdCl7dS5jYWxsKHRoaXMsQT8/ImNhbmNlbGVkIix1LkVSUl9DQU5DRUxFRCxlLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9cy5pbmhlcml0cyhMZSx1LHtfX0NBTkNFTF9fOiEwfSk7dmFyIHg9TGU7ZnVuY3Rpb24gSkEoQSxlLHQpe2xldCByPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IXJ8fHIodC5zdGF0dXMpP0EodCk6ZShuZXcgdSgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFt1LkVSUl9CQURfUkVRVUVTVCx1LkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciB4ZT1GLmhhc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LHIsbixpLGEsZyl7bGV0IGY9W107Zi5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChyKSkscy5pc051bWJlcihuKSYmZi5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUobikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmZi5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhhKSYmZi5wdXNoKCJkb21haW49IithKSxnPT09ITAmJmYucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPWYuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgcj1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xccyopKCIrdCsiKT0oW147XSopIikpO3JldHVybiByP2RlY29kZVVSSUNvbXBvbmVudChyWzNdKTpudWxsfSxyZW1vdmU6ZnVuY3Rpb24odCl7dGhpcy53cml0ZSh0LCIiLERhdGUubm93KCktODY0ZTUpfX19KCk6ZnVuY3Rpb24oKXtyZXR1cm57d3JpdGU6ZnVuY3Rpb24oKXt9LHJlYWQ6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbH0scmVtb3ZlOmZ1bmN0aW9uKCl7fX19KCk7ZnVuY3Rpb24gSEEoQSl7cmV0dXJuL14oW2Etel1bYS16XGQrXC0uXSo6KT9cL1wvL2kudGVzdChBKX1mdW5jdGlvbiBZQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXC8rJC8sIiIpKyIvIitlLnJlcGxhY2UoL15cLysvLCIiKTpBfWZ1bmN0aW9uIG5BKEEsZSl7cmV0dXJuIEEmJiFIQShlKT9ZQShBLGUpOmV9dmFyIFBlPUYuaGFzU3RhbmRhcmRCcm93c2VyRW52P2Z1bmN0aW9uKCl7bGV0IGU9Lyhtc2llfHRyaWRlbnQpL2kudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KSx0PWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoImEiKSxyO2Z1bmN0aW9uIG4oaSl7bGV0IGE9aTtyZXR1cm4gZSYmKHQuc2V0QXR0cmlidXRlKCJocmVmIixhKSxhPXQuaHJlZiksdC5zZXRBdHRyaWJ1dGUoImhyZWYiLGEpLHtocmVmOnQuaHJlZixwcm90b2NvbDp0LnByb3RvY29sP3QucHJvdG9jb2wucmVwbGFjZSgvOiQvLCIiKToiIixob3N0OnQuaG9zdCxzZWFyY2g6dC5zZWFyY2g/dC5zZWFyY2gucmVwbGFjZSgvXlw/LywiIik6IiIsaGFzaDp0Lmhhc2g/dC5oYXNoLnJlcGxhY2UoL14jLywiIik6IiIsaG9zdG5hbWU6dC5ob3N0bmFtZSxwb3J0OnQucG9ydCxwYXRobmFtZTp0LnBhdGhuYW1lLmNoYXJBdCgwKT09PSIvIj90LnBhdGhuYW1lOiIvIit0LnBhdGhuYW1lfX1yZXR1cm4gcj1uKHdpbmRvdy5sb2NhdGlvbi5ocmVmKSxmdW5jdGlvbihhKXtsZXQgZz1zLmlzU3RyaW5nKGEpP24oYSk6YTtyZXR1cm4gZy5wcm90b2NvbD09PXIucHJvdG9jb2wmJmcuaG9zdD09PXIuaG9zdH19KCk6ZnVuY3Rpb24oKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4hMH19KCk7ZnVuY3Rpb24gcUEoQSl7bGV0IGU9L14oWy0rXHddezEsMjV9KSg6P1wvXC98OikvLmV4ZWMoQSk7cmV0dXJuIGUmJmVbMV18fCIifWZ1bmN0aW9uIFVyKEEsZSl7QT1BfHwxMDtsZXQgdD1uZXcgQXJyYXkoQSkscj1uZXcgQXJyYXkoQSksbj0wLGk9MCxhO3JldHVybiBlPWUhPT12b2lkIDA/ZToxZTMsZnVuY3Rpb24oZil7bGV0IEk9RGF0ZS5ub3coKSxvPXJbaV07YXx8KGE9SSksdFtuXT1mLHJbbl09STtsZXQgQj1pLGM9MDtmb3IoO0IhPT1uOyljKz10W0IrK10sQj1CJUE7aWYobj0obisxKSVBLG49PT1pJiYoaT0oaSsxKSVBKSxJLWE8ZSlyZXR1cm47bGV0IEM9byYmSS1vO3JldHVybiBDP01hdGgucm91bmQoYyoxZTMvQyk6dm9pZCAwfX12YXIgTWU9VXI7ZnVuY3Rpb24gSmUoQSxlKXtsZXQgdD0wLHI9TWUoNTAsMjUwKTtyZXR1cm4gbj0+e2xldCBpPW4ubG9hZGVkLGE9bi5sZW5ndGhDb21wdXRhYmxlP24udG90YWw6dm9pZCAwLGc9aS10LGY9cihnKSxJPWk8PWE7dD1pO2xldCBvPXtsb2FkZWQ6aSx0b3RhbDphLHByb2dyZXNzOmE/aS9hOnZvaWQgMCxieXRlczpnLHJhdGU6Znx8dm9pZCAwLGVzdGltYXRlZDpmJiZhJiZJPyhhLWkpL2Y6dm9pZCAwLGV2ZW50Om59O29bZT8iZG93bmxvYWQiOiJ1cGxvYWQiXT0hMCxBKG8pfX12YXIgUnI9dHlwZW9mIFhNTEh0dHBSZXF1ZXN0PCJ1IixIZT1SciYmZnVuY3Rpb24oQSl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKHQscil7bGV0IG49QS5kYXRhLGk9ay5mcm9tKEEuaGVhZGVycykubm9ybWFsaXplKCksYT1BLnJlc3BvbnNlVHlwZSxnO2Z1bmN0aW9uIGYoKXtBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnVuc3Vic2NyaWJlKGcpLEEuc2lnbmFsJiZBLnNpZ25hbC5yZW1vdmVFdmVudExpc3RlbmVyKCJhYm9ydCIsZyl9bGV0IEk7aWYocy5pc0Zvcm1EYXRhKG4pKXtpZihGLmhhc1N0YW5kYXJkQnJvd3NlckVudnx8Ri5oYXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnYpaS5zZXRDb250ZW50VHlwZSghMSk7ZWxzZSBpZigoST1pLmdldENvbnRlbnRUeXBlKCkpIT09ITEpe2xldFtsLC4uLkVdPUk/SS5zcGxpdCgiOyIpLm1hcChtPT5tLnRyaW0oKSkuZmlsdGVyKEJvb2xlYW4pOltdO2kuc2V0Q29udGVudFR5cGUoW2x8fCJtdWx0aXBhcnQvZm9ybS1kYXRhIiwuLi5FXS5qb2luKCI7ICIpKX19bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IGw9QS5hdXRoLnVzZXJuYW1lfHwiIixFPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EobCsiOiIrRSkpfWxldCBCPW5BKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksQUEoQixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIGMoKXtpZighbylyZXR1cm47bGV0IGw9ay5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksbT17ZGF0YTohYXx8YT09PSJ0ZXh0Inx8YT09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOmwsY29uZmlnOkEscmVxdWVzdDpvfTtKQShmdW5jdGlvbihwKXt0KHApLGYoKX0sZnVuY3Rpb24ocCl7cihwKSxmKCl9LG0pLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9YzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoYyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihyKG5ldyB1KCJSZXF1ZXN0IGFib3J0ZWQiLHUuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe3IobmV3IHUoIk5ldHdvcmsgRXJyb3IiLHUuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBFPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixtPUEudHJhbnNpdGlvbmFsfHxCQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihFPUEudGltZW91dEVycm9yTWVzc2FnZSkscihuZXcgdShFLG0uY2xhcmlmeVRpbWVvdXRFcnJvcj91LkVUSU1FRE9VVDp1LkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LEYuaGFzU3RhbmRhcmRCcm93c2VyRW52KXtsZXQgbD1QZShCKSYmQS54c3JmQ29va2llTmFtZSYmeGUucmVhZChBLnhzcmZDb29raWVOYW1lKTtsJiZpLnNldChBLnhzcmZIZWFkZXJOYW1lLGwpfW49PT12b2lkIDAmJmkuc2V0Q29udGVudFR5cGUobnVsbCksInNldFJlcXVlc3RIZWFkZXIiaW4gbyYmcy5mb3JFYWNoKGkudG9KU09OKCksZnVuY3Rpb24oRSxtKXtvLnNldFJlcXVlc3RIZWFkZXIobSxFKX0pLHMuaXNVbmRlZmluZWQoQS53aXRoQ3JlZGVudGlhbHMpfHwoby53aXRoQ3JlZGVudGlhbHM9ISFBLndpdGhDcmVkZW50aWFscyksYSYmYSE9PSJqc29uIiYmKG8ucmVzcG9uc2VUeXBlPUEucmVzcG9uc2VUeXBlKSx0eXBlb2YgQS5vbkRvd25sb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm8uYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLEplKEEub25Eb3dubG9hZFByb2dyZXNzLCEwKSksdHlwZW9mIEEub25VcGxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby51cGxvYWQmJm8udXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixKZShBLm9uVXBsb2FkUHJvZ3Jlc3MpKSwoQS5jYW5jZWxUb2tlbnx8QS5zaWduYWwpJiYoZz1sPT57byYmKHIoIWx8fGwudHlwZT9uZXcgeChudWxsLEEsbyk6bCksby5hYm9ydCgpLG89bnVsbCl9LEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4uc3Vic2NyaWJlKGcpLEEuc2lnbmFsJiYoQS5zaWduYWwuYWJvcnRlZD9nKCk6QS5zaWduYWwuYWRkRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGcpKSk7bGV0IEM9cUEoQik7aWYoQyYmRi5wcm90b2NvbHMuaW5kZXhPZihDKT09PS0xKXtyKG5ldyB1KCJVbnN1cHBvcnRlZCBwcm90b2NvbCAiK0MrIjoiLHUuRVJSX0JBRF9SRVFVRVNULEEpKTtyZXR1cm59by5zZW5kKG58fG51bGwpfSl9O3ZhciBLQT17aHR0cDpDQSx4aHI6SGV9O3MuZm9yRWFjaChLQSwoQSxlKT0+e2lmKEEpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwibmFtZSIse3ZhbHVlOmV9KX1jYXRjaHt9T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsImFkYXB0ZXJOYW1lIix7dmFsdWU6ZX0pfX0pO3ZhciBZZT1BPT5gLSAke0F9YCxOcj1BPT5zLmlzRnVuY3Rpb24oQSl8fEE9PT1udWxsfHxBPT09ITEsUUE9e2dldEFkYXB0ZXI6QT0+e0E9cy5pc0FycmF5KEEpP0E6W0FdO2xldHtsZW5ndGg6ZX09QSx0LHIsbj17fTtmb3IobGV0IGk9MDtpPGU7aSsrKXt0PUFbaV07bGV0IGE7aWYocj10LCFOcih0KSYmKHI9S0FbKGE9U3RyaW5nKHQpKS50b0xvd2VyQ2FzZSgpXSxyPT09dm9pZCAwKSl0aHJvdyBuZXcgdShgVW5rbm93biBhZGFwdGVyICcke2F9J2ApO2lmKHIpYnJlYWs7blthfHwiIyIraV09cn1pZighcil7bGV0IGk9T2JqZWN0LmVudHJpZXMobikubWFwKChbZyxmXSk9PmBhZGFwdGVyICR7Z30gYCsoZj09PSExPyJpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBlbnZpcm9ubWVudCI6ImlzIG5vdCBhdmFpbGFibGUgaW4gdGhlIGJ1aWxkIikpLGE9ZT9pLmxlbmd0aD4xP2BzaW5jZSA6CmAraS5tYXAoWWUpLmpvaW4oYApgKToiICIrWWUoaVswXSk6ImFzIG5vIGFkYXB0ZXIgc3BlY2lmaWVkIjt0aHJvdyBuZXcgdSgiVGhlcmUgaXMgbm8gc3VpdGFibGUgYWRhcHRlciB0byBkaXNwYXRjaCB0aGUgcmVxdWVzdCAiK2EsIkVSUl9OT1RfU1VQUE9SVCIpfXJldHVybiByfSxhZGFwdGVyczpLQX07ZnVuY3Rpb24gdkEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IHgobnVsbCxBKX1mdW5jdGlvbiB1QShBKXtyZXR1cm4gdkEoQSksQS5oZWFkZXJzPWsuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksUUEuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fHYuYWRhcHRlcikoQSkudGhlbihmdW5jdGlvbihyKXtyZXR1cm4gdkEoQSksci5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLHIpLHIuaGVhZGVycz1rLmZyb20oci5oZWFkZXJzKSxyfSxmdW5jdGlvbihyKXtyZXR1cm4gckEocil8fCh2QShBKSxyJiZyLnJlc3BvbnNlJiYoci5yZXNwb25zZS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLHIucmVzcG9uc2UpLHIucmVzcG9uc2UuaGVhZGVycz1rLmZyb20oci5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KHIpfSl9dmFyIHFlPUE9PkEgaW5zdGFuY2VvZiBrP0EudG9KU09OKCk6QTtmdW5jdGlvbiBUKEEsZSl7ZT1lfHx7fTtsZXQgdD17fTtmdW5jdGlvbiByKEksbyxCKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KEkpJiZzLmlzUGxhaW5PYmplY3Qobyk/cy5tZXJnZS5jYWxsKHtjYXNlbGVzczpCfSxJLG8pOnMuaXNQbGFpbk9iamVjdChvKT9zLm1lcmdlKHt9LG8pOnMuaXNBcnJheShvKT9vLnNsaWNlKCk6b31mdW5jdGlvbiBuKEksbyxCKXtpZihzLmlzVW5kZWZpbmVkKG8pKXtpZighcy5pc1VuZGVmaW5lZChJKSlyZXR1cm4gcih2b2lkIDAsSSxCKX1lbHNlIHJldHVybiByKEksbyxCKX1mdW5jdGlvbiBpKEksbyl7aWYoIXMuaXNVbmRlZmluZWQobykpcmV0dXJuIHIodm9pZCAwLG8pfWZ1bmN0aW9uIGEoSSxvKXtpZihzLmlzVW5kZWZpbmVkKG8pKXtpZighcy5pc1VuZGVmaW5lZChJKSlyZXR1cm4gcih2b2lkIDAsSSl9ZWxzZSByZXR1cm4gcih2b2lkIDAsbyl9ZnVuY3Rpb24gZyhJLG8sQil7aWYoQiBpbiBlKXJldHVybiByKEksbyk7aWYoQiBpbiBBKXJldHVybiByKHZvaWQgMCxJKX1sZXQgZj17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6YSx0cmFuc2Zvcm1SZXF1ZXN0OmEsdHJhbnNmb3JtUmVzcG9uc2U6YSxwYXJhbXNTZXJpYWxpemVyOmEsdGltZW91dDphLHRpbWVvdXRNZXNzYWdlOmEsd2l0aENyZWRlbnRpYWxzOmEsYWRhcHRlcjphLHJlc3BvbnNlVHlwZTphLHhzcmZDb29raWVOYW1lOmEseHNyZkhlYWRlck5hbWU6YSxvblVwbG9hZFByb2dyZXNzOmEsb25Eb3dubG9hZFByb2dyZXNzOmEsZGVjb21wcmVzczphLG1heENvbnRlbnRMZW5ndGg6YSxtYXhCb2R5TGVuZ3RoOmEsYmVmb3JlUmVkaXJlY3Q6YSx0cmFuc3BvcnQ6YSxodHRwQWdlbnQ6YSxodHRwc0FnZW50OmEsY2FuY2VsVG9rZW46YSxzb2NrZXRQYXRoOmEscmVzcG9uc2VFbmNvZGluZzphLHZhbGlkYXRlU3RhdHVzOmcsaGVhZGVyczooSSxvKT0+bihxZShJKSxxZShvKSwhMCl9O3JldHVybiBzLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihvKXtsZXQgQj1mW29dfHxuLGM9QihBW29dLGVbb10sbyk7cy5pc1VuZGVmaW5lZChjKSYmQiE9PWd8fCh0W29dPWMpfSksdH12YXIgZEE9IjEuNi4xIjt2YXIgakE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57akFbQV09ZnVuY3Rpb24ocil7cmV0dXJuIHR5cGVvZiByPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIEtlPXt9O2pBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQscil7ZnVuY3Rpb24gbihpLGEpe3JldHVybiJbQXhpb3MgdiIrZEErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiAnIitpKyInIithKyhyPyIuICIrcjoiIil9cmV0dXJuKGksYSxnKT0+e2lmKGU9PT0hMSl0aHJvdyBuZXcgdShuKGEsIiBoYXMgYmVlbiByZW1vdmVkIisodD8iIGluICIrdDoiIikpLHUuRVJSX0RFUFJFQ0FURUQpO3JldHVybiB0JiYhS2VbYV0mJihLZVthXT0hMCxjb25zb2xlLndhcm4obihhLCIgaGFzIGJlZW4gZGVwcmVjYXRlZCBzaW5jZSB2Iit0KyIgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmVhciBmdXR1cmUiKSkpLGU/ZShpLGEsZyk6ITB9fTtmdW5jdGlvbiBPcihBLGUsdCl7aWYodHlwZW9mIEEhPSJvYmplY3QiKXRocm93IG5ldyB1KCJvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0Iix1LkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtsZXQgcj1PYmplY3Qua2V5cyhBKSxuPXIubGVuZ3RoO2Zvcig7bi0tID4wOyl7bGV0IGk9cltuXSxhPWVbaV07aWYoYSl7bGV0IGc9QVtpXSxmPWc9PT12b2lkIDB8fGEoZyxpLEEpO2lmKGYhPT0hMCl0aHJvdyBuZXcgdSgib3B0aW9uICIraSsiIG11c3QgYmUgIitmLHUuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2NvbnRpbnVlfWlmKHQhPT0hMCl0aHJvdyBuZXcgdSgiVW5rbm93biBvcHRpb24gIitpLHUuRVJSX0JBRF9PUFRJT04pfX12YXIgcEE9e2Fzc2VydE9wdGlvbnM6T3IsdmFsaWRhdG9yczpqQX07dmFyIFA9cEEudmFsaWRhdG9ycyxXPWNsYXNze2NvbnN0cnVjdG9yKGUpe3RoaXMuZGVmYXVsdHM9ZSx0aGlzLmludGVyY2VwdG9ycz17cmVxdWVzdDpuZXcgVEEscmVzcG9uc2U6bmV3IFRBfX1yZXF1ZXN0KGUsdCl7dHlwZW9mIGU9PSJzdHJpbmciPyh0PXR8fHt9LHQudXJsPWUpOnQ9ZXx8e30sdD1UKHRoaXMuZGVmYXVsdHMsdCk7bGV0e3RyYW5zaXRpb25hbDpyLHBhcmFtc1NlcmlhbGl6ZXI6bixoZWFkZXJzOml9PXQ7ciE9PXZvaWQgMCYmcEEuYXNzZXJ0T3B0aW9ucyhyLHtzaWxlbnRKU09OUGFyc2luZzpQLnRyYW5zaXRpb25hbChQLmJvb2xlYW4pLGZvcmNlZEpTT05QYXJzaW5nOlAudHJhbnNpdGlvbmFsKFAuYm9vbGVhbiksY2xhcmlmeVRpbWVvdXRFcnJvcjpQLnRyYW5zaXRpb25hbChQLmJvb2xlYW4pfSwhMSksbiE9bnVsbCYmKHMuaXNGdW5jdGlvbihuKT90LnBhcmFtc1NlcmlhbGl6ZXI9e3NlcmlhbGl6ZTpufTpwQS5hc3NlcnRPcHRpb25zKG4se2VuY29kZTpQLmZ1bmN0aW9uLHNlcmlhbGl6ZTpQLmZ1bmN0aW9ufSwhMCkpLHQubWV0aG9kPSh0Lm1ldGhvZHx8dGhpcy5kZWZhdWx0cy5tZXRob2R8fCJnZXQiKS50b0xvd2VyQ2FzZSgpO2xldCBhPWkmJnMubWVyZ2UoaS5jb21tb24saVt0Lm1ldGhvZF0pO2kmJnMuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJwb3N0IiwicHV0IiwicGF0Y2giLCJjb21tb24iXSxsPT57ZGVsZXRlIGlbbF19KSx0LmhlYWRlcnM9ay5jb25jYXQoYSxpKTtsZXQgZz1bXSxmPSEwO3RoaXMuaW50ZXJjZXB0b3JzLnJlcXVlc3QuZm9yRWFjaChmdW5jdGlvbihFKXt0eXBlb2YgRS5ydW5XaGVuPT0iZnVuY3Rpb24iJiZFLnJ1bldoZW4odCk9PT0hMXx8KGY9ZiYmRS5zeW5jaHJvbm91cyxnLnVuc2hpZnQoRS5mdWxmaWxsZWQsRS5yZWplY3RlZCkpfSk7bGV0IEk9W107dGhpcy5pbnRlcmNlcHRvcnMucmVzcG9uc2UuZm9yRWFjaChmdW5jdGlvbihFKXtJLnB1c2goRS5mdWxmaWxsZWQsRS5yZWplY3RlZCl9KTtsZXQgbyxCPTAsYztpZighZil7bGV0IGw9W3VBLmJpbmQodGhpcyksdm9pZCAwXTtmb3IobC51bnNoaWZ0LmFwcGx5KGwsZyksbC5wdXNoLmFwcGx5KGwsSSksYz1sLmxlbmd0aCxvPVByb21pc2UucmVzb2x2ZSh0KTtCPGM7KW89by50aGVuKGxbQisrXSxsW0IrK10pO3JldHVybiBvfWM9Zy5sZW5ndGg7bGV0IEM9dDtmb3IoQj0wO0I8Yzspe2xldCBsPWdbQisrXSxFPWdbQisrXTt0cnl7Qz1sKEMpfWNhdGNoKG0pe0UuY2FsbCh0aGlzLG0pO2JyZWFrfX10cnl7bz11QS5jYWxsKHRoaXMsQyl9Y2F0Y2gobCl7cmV0dXJuIFByb21pc2UucmVqZWN0KGwpfWZvcihCPTAsYz1JLmxlbmd0aDtCPGM7KW89by50aGVuKElbQisrXSxJW0IrK10pO3JldHVybiBvfWdldFVyaShlKXtlPVQodGhpcy5kZWZhdWx0cyxlKTtsZXQgdD1uQShlLmJhc2VVUkwsZS51cmwpO3JldHVybiBBQSh0LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplcil9fTtzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwib3B0aW9ucyJdLGZ1bmN0aW9uKGUpe1cucHJvdG90eXBlW2VdPWZ1bmN0aW9uKHQscil7cmV0dXJuIHRoaXMucmVxdWVzdChUKHJ8fHt9LHttZXRob2Q6ZSx1cmw6dCxkYXRhOihyfHx7fSkuZGF0YX0pKX19KTtzLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbihlKXtmdW5jdGlvbiB0KHIpe3JldHVybiBmdW5jdGlvbihpLGEsZyl7cmV0dXJuIHRoaXMucmVxdWVzdChUKGd8fHt9LHttZXRob2Q6ZSxoZWFkZXJzOnI/eyJDb250ZW50LVR5cGUiOiJtdWx0aXBhcnQvZm9ybS1kYXRhIn06e30sdXJsOmksZGF0YTphfSkpfX1XLnByb3RvdHlwZVtlXT10KCksVy5wcm90b3R5cGVbZSsiRm9ybSJdPXQoITApfSk7dmFyIGlBPVc7dmFyIFdBPWNsYXNzIEF7Y29uc3RydWN0b3IoZSl7aWYodHlwZW9mIGUhPSJmdW5jdGlvbiIpdGhyb3cgbmV3IFR5cGVFcnJvcigiZXhlY3V0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uLiIpO2xldCB0O3RoaXMucHJvbWlzZT1uZXcgUHJvbWlzZShmdW5jdGlvbihpKXt0PWl9KTtsZXQgcj10aGlzO3RoaXMucHJvbWlzZS50aGVuKG49PntpZighci5fbGlzdGVuZXJzKXJldHVybjtsZXQgaT1yLl9saXN0ZW5lcnMubGVuZ3RoO2Zvcig7aS0tID4wOylyLl9saXN0ZW5lcnNbaV0obik7ci5fbGlzdGVuZXJzPW51bGx9KSx0aGlzLnByb21pc2UudGhlbj1uPT57bGV0IGksYT1uZXcgUHJvbWlzZShnPT57ci5zdWJzY3JpYmUoZyksaT1nfSkudGhlbihuKTtyZXR1cm4gYS5jYW5jZWw9ZnVuY3Rpb24oKXtyLnVuc3Vic2NyaWJlKGkpfSxhfSxlKGZ1bmN0aW9uKGksYSxnKXtyLnJlYXNvbnx8KHIucmVhc29uPW5ldyB4KGksYSxnKSx0KHIucmVhc29uKSl9KX10aHJvd0lmUmVxdWVzdGVkKCl7aWYodGhpcy5yZWFzb24pdGhyb3cgdGhpcy5yZWFzb259c3Vic2NyaWJlKGUpe2lmKHRoaXMucmVhc29uKXtlKHRoaXMucmVhc29uKTtyZXR1cm59dGhpcy5fbGlzdGVuZXJzP3RoaXMuX2xpc3RlbmVycy5wdXNoKGUpOnRoaXMuX2xpc3RlbmVycz1bZV19dW5zdWJzY3JpYmUoZSl7aWYoIXRoaXMuX2xpc3RlbmVycylyZXR1cm47bGV0IHQ9dGhpcy5fbGlzdGVuZXJzLmluZGV4T2YoZSk7dCE9PS0xJiZ0aGlzLl9saXN0ZW5lcnMuc3BsaWNlKHQsMSl9c3RhdGljIHNvdXJjZSgpe2xldCBlO3JldHVybnt0b2tlbjpuZXcgQShmdW5jdGlvbihuKXtlPW59KSxjYW5jZWw6ZX19fSx2ZT1XQTtmdW5jdGlvbiBfQShBKXtyZXR1cm4gZnVuY3Rpb24odCl7cmV0dXJuIEEuYXBwbHkobnVsbCx0KX19ZnVuY3Rpb24gekEoQSl7cmV0dXJuIHMuaXNPYmplY3QoQSkmJkEuaXNBeGlvc0Vycm9yPT09ITB9dmFyIFZBPXtDb250aW51ZToxMDAsU3dpdGNoaW5nUHJvdG9jb2xzOjEwMSxQcm9jZXNzaW5nOjEwMixFYXJseUhpbnRzOjEwMyxPazoyMDAsQ3JlYXRlZDoyMDEsQWNjZXB0ZWQ6MjAyLE5vbkF1dGhvcml0YXRpdmVJbmZvcm1hdGlvbjoyMDMsTm9Db250ZW50OjIwNCxSZXNldENvbnRlbnQ6MjA1LFBhcnRpYWxDb250ZW50OjIwNixNdWx0aVN0YXR1czoyMDcsQWxyZWFkeVJlcG9ydGVkOjIwOCxJbVVzZWQ6MjI2LE11bHRpcGxlQ2hvaWNlczozMDAsTW92ZWRQZXJtYW5lbnRseTozMDEsRm91bmQ6MzAyLFNlZU90aGVyOjMwMyxOb3RNb2RpZmllZDozMDQsVXNlUHJveHk6MzA1LFVudXNlZDozMDYsVGVtcG9yYXJ5UmVkaXJlY3Q6MzA3LFBlcm1hbmVudFJlZGlyZWN0OjMwOCxCYWRSZXF1ZXN0OjQwMCxVbmF1dGhvcml6ZWQ6NDAxLFBheW1lbnRSZXF1aXJlZDo0MDIsRm9yYmlkZGVuOjQwMyxOb3RGb3VuZDo0MDQsTWV0aG9kTm90QWxsb3dlZDo0MDUsTm90QWNjZXB0YWJsZTo0MDYsUHJveHlBdXRoZW50aWNhdGlvblJlcXVpcmVkOjQwNyxSZXF1ZXN0VGltZW91dDo0MDgsQ29uZmxpY3Q6NDA5LEdvbmU6NDEwLExlbmd0aFJlcXVpcmVkOjQxMSxQcmVjb25kaXRpb25GYWlsZWQ6NDEyLFBheWxvYWRUb29MYXJnZTo0MTMsVXJpVG9vTG9uZzo0MTQsVW5zdXBwb3J0ZWRNZWRpYVR5cGU6NDE1LFJhbmdlTm90U2F0aXNmaWFibGU6NDE2LEV4cGVjdGF0aW9uRmFpbGVkOjQxNyxJbUFUZWFwb3Q6NDE4LE1pc2RpcmVjdGVkUmVxdWVzdDo0MjEsVW5wcm9jZXNzYWJsZUVudGl0eTo0MjIsTG9ja2VkOjQyMyxGYWlsZWREZXBlbmRlbmN5OjQyNCxUb29FYXJseTo0MjUsVXBncmFkZVJlcXVpcmVkOjQyNixQcmVjb25kaXRpb25SZXF1aXJlZDo0MjgsVG9vTWFueVJlcXVlc3RzOjQyOSxSZXF1ZXN0SGVhZGVyRmllbGRzVG9vTGFyZ2U6NDMxLFVuYXZhaWxhYmxlRm9yTGVnYWxSZWFzb25zOjQ1MSxJbnRlcm5hbFNlcnZlckVycm9yOjUwMCxOb3RJbXBsZW1lbnRlZDo1MDEsQmFkR2F0ZXdheTo1MDIsU2VydmljZVVuYXZhaWxhYmxlOjUwMyxHYXRld2F5VGltZW91dDo1MDQsSHR0cFZlcnNpb25Ob3RTdXBwb3J0ZWQ6NTA1LFZhcmlhbnRBbHNvTmVnb3RpYXRlczo1MDYsSW5zdWZmaWNpZW50U3RvcmFnZTo1MDcsTG9vcERldGVjdGVkOjUwOCxOb3RFeHRlbmRlZDo1MTAsTmV0d29ya0F1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NTExfTtPYmplY3QuZW50cmllcyhWQSkuZm9yRWFjaCgoW0EsZV0pPT57VkFbZV09QX0pO3ZhciBqZT1WQTtmdW5jdGlvbiBXZShBKXtsZXQgZT1uZXcgaUEoQSksdD1aKGlBLnByb3RvdHlwZS5yZXF1ZXN0LGUpO3JldHVybiBzLmV4dGVuZCh0LGlBLnByb3RvdHlwZSxlLHthbGxPd25LZXlzOiEwfSkscy5leHRlbmQodCxlLG51bGwse2FsbE93bktleXM6ITB9KSx0LmNyZWF0ZT1mdW5jdGlvbihuKXtyZXR1cm4gV2UoVChBLG4pKX0sdH12YXIgeT1XZSh2KTt5LkF4aW9zPWlBO3kuQ2FuY2VsZWRFcnJvcj14O3kuQ2FuY2VsVG9rZW49dmU7eS5pc0NhbmNlbD1yQTt5LlZFUlNJT049ZEE7eS50b0Zvcm1EYXRhPUw7eS5BeGlvc0Vycm9yPXU7eS5DYW5jZWw9eS5DYW5jZWxlZEVycm9yO3kuYWxsPWZ1bmN0aW9uKGUpe3JldHVybiBQcm9taXNlLmFsbChlKX07eS5zcHJlYWQ9X0E7eS5pc0F4aW9zRXJyb3I9ekE7eS5tZXJnZUNvbmZpZz1UO3kuQXhpb3NIZWFkZXJzPWs7eS5mb3JtVG9KU09OPUE9PmZBKHMuaXNIVE1MRm9ybShBKT9uZXcgRm9ybURhdGEoQSk6QSk7eS5nZXRBZGFwdGVyPVFBLmdldEFkYXB0ZXI7eS5IdHRwU3RhdHVzQ29kZT1qZTt5LmRlZmF1bHQ9eTt2YXIgSj15O3ZhcntBeGlvczpJbyxBeGlvc0Vycm9yOmdvLENhbmNlbGVkRXJyb3I6bG8saXNDYW5jZWw6Q28sQ2FuY2VsVG9rZW46Y28sVkVSU0lPTjpCbyxhbGw6Zm8sQ2FuY2VsOkVvLGlzQXhpb3NFcnJvcjpRbyxzcHJlYWQ6dW8sdG9Gb3JtRGF0YTpwbyxBeGlvc0hlYWRlcnM6bW8sSHR0cFN0YXR1c0NvZGU6aG8sZm9ybVRvSlNPTjp5byxnZXRBZGFwdGVyOndvLG1lcmdlQ29uZmlnOkRvfT1KO3ZhciB6ZT1TeW1ib2woIkNvbWxpbmsucHJveHkiKSxHcj1TeW1ib2woIkNvbWxpbmsuZW5kcG9pbnQiKSwkQT1TeW1ib2woIkNvbWxpbmsucmVsZWFzZVByb3h5IiksWkE9U3ltYm9sKCJDb21saW5rLmZpbmFsaXplciIpLGhBPVN5bWJvbCgiQ29tbGluay50aHJvd24iKSxWZT1BPT50eXBlb2YgQT09Im9iamVjdCImJkEhPT1udWxsfHx0eXBlb2YgQT09ImZ1bmN0aW9uIixUcj17Y2FuSGFuZGxlOkE9PlZlKEEpJiZBW3plXSxzZXJpYWxpemUoQSl7bGV0e3BvcnQxOmUscG9ydDI6dH09bmV3IE1lc3NhZ2VDaGFubmVsO3JldHVybiBYZShBLGUpLFt0LFt0XV19LGRlc2VyaWFsaXplKEEpe3JldHVybiBBLnN0YXJ0KCksQWUoQSl9fSxMcj17Y2FuSGFuZGxlOkE9PlZlKEEpJiZoQSBpbiBBLHNlcmlhbGl6ZSh7dmFsdWU6QX0pe2xldCBlO3JldHVybiBBIGluc3RhbmNlb2YgRXJyb3I/ZT17aXNFcnJvcjohMCx2YWx1ZTp7bWVzc2FnZTpBLm1lc3NhZ2UsbmFtZTpBLm5hbWUsc3RhY2s6QS5zdGFja319OmU9e2lzRXJyb3I6ITEsdmFsdWU6QX0sW2UsW11dfSxkZXNlcmlhbGl6ZShBKXt0aHJvdyBBLmlzRXJyb3I/T2JqZWN0LmFzc2lnbihuZXcgRXJyb3IoQS52YWx1ZS5tZXNzYWdlKSxBLnZhbHVlKTpBLnZhbHVlfX0sWmU9bmV3IE1hcChbWyJwcm94eSIsVHJdLFsidGhyb3ciLExyXV0pO2Z1bmN0aW9uIHhyKEEsZSl7Zm9yKGxldCB0IG9mIEEpaWYoZT09PXR8fHQ9PT0iKiJ8fHQgaW5zdGFuY2VvZiBSZWdFeHAmJnQudGVzdChlKSlyZXR1cm4hMDtyZXR1cm4hMX1mdW5jdGlvbiBYZShBLGU9Z2xvYmFsVGhpcyx0PVsiKiJdKXtlLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIHIobil7aWYoIW58fCFuLmRhdGEpcmV0dXJuO2lmKCF4cih0LG4ub3JpZ2luKSl7Y29uc29sZS53YXJuKGBJbnZhbGlkIG9yaWdpbiAnJHtuLm9yaWdpbn0nIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6YSxwYXRoOmd9PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LG4uZGF0YSksZj0obi5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChIKSxJO3RyeXtsZXQgbz1nLnNsaWNlKDAsLTEpLnJlZHVjZSgoYyxDKT0+Y1tDXSxBKSxCPWcucmVkdWNlKChjLEMpPT5jW0NdLEEpO3N3aXRjaChhKXtjYXNlIkdFVCI6ST1CO2JyZWFrO2Nhc2UiU0VUIjpvW2cuc2xpY2UoLTEpWzBdXT1IKG4uZGF0YS52YWx1ZSksST0hMDticmVhaztjYXNlIkFQUExZIjpJPUIuYXBwbHkobyxmKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBjPW5ldyBCKC4uLmYpO0k9WXIoYyl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTpjLHBvcnQyOkN9PW5ldyBNZXNzYWdlQ2hhbm5lbDtYZShBLEMpLEk9ZWUoYyxbY10pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6ST12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKG8pe0k9e3ZhbHVlOm8sW2hBXTowfX1Qcm9taXNlLnJlc29sdmUoSSkuY2F0Y2gobz0+KHt2YWx1ZTpvLFtoQV06MH0pKS50aGVuKG89PntsZXRbQixjXT1EQShvKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxCKSx7aWQ6aX0pLGMpLGE9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLHIpLCRlKGUpLFpBIGluIEEmJnR5cGVvZiBBW1pBXT09ImZ1bmN0aW9uIiYmQVtaQV0oKSl9KS5jYXRjaChvPT57bGV0W0IsY109REEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtoQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LEIpLHtpZDppfSksYyl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBQcihBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiAkZShBKXtQcihBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIEFlKEEsZSl7cmV0dXJuIFhBKEEsW10sZSl9ZnVuY3Rpb24gbUEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIEF0KEEpe3JldHVybiBfKEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+eyRlKEEpfSl9dmFyIHlBPW5ldyBXZWFrTWFwLHdBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPSh5QS5nZXQoQSl8fDApLTE7eUEuc2V0KEEsZSksZT09PTAmJkF0KEEpfSk7ZnVuY3Rpb24gTXIoQSxlKXtsZXQgdD0oeUEuZ2V0KGUpfHwwKSsxO3lBLnNldChlLHQpLHdBJiZ3QS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gSnIoQSl7d0EmJndBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gWEEoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgcj0hMSxuPW5ldyBQcm94eSh0LHtnZXQoaSxhKXtpZihtQShyKSxhPT09JEEpcmV0dXJuKCk9PntKcihuKSxBdChBKSxyPSEwfTtpZihhPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9Pm59O2xldCBnPV8oQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKGY9PmYudG9TdHJpbmcoKSl9KS50aGVuKEgpO3JldHVybiBnLnRoZW4uYmluZChnKX1yZXR1cm4gWEEoQSxbLi4uZSxhXSl9LHNldChpLGEsZyl7bUEocik7bGV0W2YsSV09REEoZyk7cmV0dXJuIF8oQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGFdLm1hcChvPT5vLnRvU3RyaW5nKCkpLHZhbHVlOmZ9LEkpLnRoZW4oSCl9LGFwcGx5KGksYSxnKXttQShyKTtsZXQgZj1lW2UubGVuZ3RoLTFdO2lmKGY9PT1HcilyZXR1cm4gXyhBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKEgpO2lmKGY9PT0iYmluZCIpcmV0dXJuIFhBKEEsZS5zbGljZSgwLC0xKSk7bGV0W0ksb109X2UoZyk7cmV0dXJuIF8oQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoQj0+Qi50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6SX0sbykudGhlbihIKX0sY29uc3RydWN0KGksYSl7bUEocik7bGV0W2csZl09X2UoYSk7cmV0dXJuIF8oQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKEk9PkkudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Omd9LGYpLnRoZW4oSCl9fSk7cmV0dXJuIE1yKG4sQSksbn1mdW5jdGlvbiBIcihBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBfZShBKXtsZXQgZT1BLm1hcChEQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLEhyKGUubWFwKHQ9PnRbMV0pKV19dmFyIGV0PW5ldyBXZWFrTWFwO2Z1bmN0aW9uIGVlKEEsZSl7cmV0dXJuIGV0LnNldChBLGUpLEF9ZnVuY3Rpb24gWXIoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W3plXTohMH0pfWZ1bmN0aW9uIERBKEEpe2ZvcihsZXRbZSx0XW9mIFplKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbcixuXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpyfSxuXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZXQuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gSChBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBaZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIF8oQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShyPT57bGV0IG49cXIoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkoYSl7IWEuZGF0YXx8IWEuZGF0YS5pZHx8YS5kYXRhLmlkIT09bnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSkscihhLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOm59LGUpLHQpfSl9ZnVuY3Rpb24gcXIoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIHJ0KEEpe2xldCBlPUFlKEEpLHQ9QTtyZXR1cm4gdC53b3JrZXJQcm94eT1lLHQub3JpZ2luYWxUZXJtaW5hdGU9dC50ZXJtaW5hdGUsdC50ZXJtaW5hdGU9KCk9Pnt0LndvcmtlclByb3h5WyRBXSgpLHQub3JpZ2luYWxUZXJtaW5hdGUoKX0se3dvcmtlclByb3h5OmUsd29ya2VyOnR9fWFzeW5jIGZ1bmN0aW9uIEtyKEEsZSl7bGV0IHQ7aWYoQSE9bnVsbCl7bGV0IGE9QTtyZXR1cm4gYS53b3JrZXJQcm94eSE9PXZvaWQgMD8odD1hLndvcmtlclByb3h5LHt3b3JrZXJQcm94eTp0LHdvcmtlcjphfSk6cnQoQSl9bGV0IHI9dHlwZW9mIGU+InUiP1kucGlwZWxpbmVXb3JrZXJVcmw6ZSxuPW51bGwsaT1ZLndlYldvcmtlcnNVcmw7aWYodHlwZW9mIGk8InUiKXtjb25zb2xlLndhcm4oIml0a0NvbmZpZyB3ZWJXb3JrZXJzVXJsIGlzIGRlcHJlY2F0ZWQuIFBsZWFzZSB1c2UgcGlwZWxpbmVXb3JrZXJVcmwgd2l0aCB0aGUgZnVsbCBwYXRoIHRvIHRoZSBwaXBlbGluZSB3b3JrZXIuIik7bGV0IGE9Im1pbi4iLGc9aTtpZihnLnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IGY9YXdhaXQgSi5nZXQoYCR7Z30vYnVuZGxlcy9waXBlbGluZS4ke2F9d29ya2VyLmpzYCx7cmVzcG9uc2VUeXBlOiJibG9iIn0pLEk9VVJMLmNyZWF0ZU9iamVjdFVSTChmLmRhdGEpO249bmV3IFdvcmtlcihJLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBuPW5ldyBXb3JrZXIoYCR7Z30vYnVuZGxlcy9waXBlbGluZS4ke2F9d29ya2VyLmpzYCx7dHlwZToibW9kdWxlIn0pfWVsc2UgaWYocj09PW51bGwpbj1uZXcgV29ya2VyKG5ldyBVUkwoIi4vd2ViLXdvcmtlcnMvaXRrLXdhc20tcGlwZWxpbmUud29ya2VyLmpzIixpbXBvcnQubWV0YS51cmwpLHt0eXBlOiJtb2R1bGUifSk7ZWxzZSBpZihyLnN0YXJ0c1dpdGgoImh0dHAiKSl7bGV0IGE9YXdhaXQgSi5nZXQocix7cmVzcG9uc2VUeXBlOiJibG9iIn0pLGc9VVJMLmNyZWF0ZU9iamVjdFVSTChhLmRhdGEpO249bmV3IFdvcmtlcihnLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBuPW5ldyBXb3JrZXIocix7dHlwZToibW9kdWxlIn0pO3JldHVybiBydChuKX12YXIgbnQ9S3I7dmFyIHZyO2Z1bmN0aW9uIGl0KCl7cmV0dXJuIHZyfXZhciBqcjtmdW5jdGlvbiBhdCgpe3JldHVybiBqcn1mdW5jdGlvbiBXcihBKXtyZXR1cm5bQS5kYXRhLEEuZGlyZWN0aW9uXX12YXIgdGU9V3I7ZnVuY3Rpb24gX3IoQSl7cmV0dXJuW0EucG9pbnRzLEEucG9pbnREYXRhLEEuY2VsbHMsQS5jZWxsRGF0YV19dmFyIG90PV9yO2FzeW5jIGZ1bmN0aW9uIHpyKEEsZSl7bGV0IHQ9InVua25vd24iO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IHI9YCR7dH0ud2FzbWAsaT0oYXdhaXQgSi5nZXQocix7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KSkuZGF0YTtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6aX0pfXZhciBzdD16cjt2YXIgSXQ9YXN5bmMoKT0+V2ViQXNzZW1ibHkudmFsaWRhdGUobmV3IFVpbnQ4QXJyYXkoWzAsOTcsMTE1LDEwOSwxLDAsMCwwLDEsNSwxLDk2LDAsMSwxMjMsMywyLDEsMCwxMCwxMCwxLDgsMCw2NSwwLDI1MywxNSwyNTMsOTgsMTFdKSk7dmFyIEN0PXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPT0iZnVuY3Rpb24iLGd0PW5ldyBUZXh0RW5jb2RlcixsdD1uZXcgVGV4dERlY29kZXIoInV0Zi04Iik7ZnVuY3Rpb24gTShBLGUpe2xldCB0PXtmbGFnczoiciIsZW5jb2Rpbmc6ImJpbmFyeSJ9LHI9QS5mc19vcGVuKGUsdC5mbGFncyksaT1BLmZzX3N0YXQoZSkuc2l6ZSxhPW51bGw7Q3Q/YT1uZXcgU2hhcmVkQXJyYXlCdWZmZXIoaSk6YT1uZXcgQXJyYXlCdWZmZXIoaSk7bGV0IGc9bmV3IFVpbnQ4QXJyYXkoYSk7cmV0dXJuIEEuZnNfcmVhZChyLGcsMCxpLDApLEEuZnNfY2xvc2UociksZ31mdW5jdGlvbiBjdChBLGUsdCl7bGV0IHI9bnVsbDtDdD9yPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcih0KTpyPW5ldyBBcnJheUJ1ZmZlcih0KTtsZXQgbj1uZXcgVWludDhBcnJheShyKSxpPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixlLHQpO3JldHVybiBuLnNldChpKSxufWZ1bmN0aW9uIFMoQSxlLHQscil7bGV0IG49MDtyZXR1cm4gZSE9PW51bGwmJihuPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2FycmF5X2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQscixlLmJ1ZmZlci5ieXRlTGVuZ3RoXSksQS5IRUFQVTguc2V0KG5ldyBVaW50OEFycmF5KGUuYnVmZmVyKSxuKSksbn1mdW5jdGlvbiB6KEEsZSx0KXtsZXQgcj1KU09OLnN0cmluZ2lmeShlKSxuPUEuY2NhbGwoIml0a193YXNtX2lucHV0X2pzb25fYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxyLmxlbmd0aF0pO0Eud3JpdGVBc2NpaVRvTWVtb3J5KHIsbiwhMSl9ZnVuY3Rpb24gTihBLGUsdCxyKXtsZXQgbj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxpPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pLGE9Y3QoQSxuLGkpO3JldHVybiBiKHIsYS5idWZmZXIpfWZ1bmN0aW9uIHJlKEEsZSl7bGV0IHQ9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2pzb25fYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiXSxbMCxlXSkscj1BLkFzY2lpVG9TdHJpbmcodCk7cmV0dXJuIEpTT04ucGFyc2Uocil9ZnVuY3Rpb24gVnIoQSxlLHQscil7ciE9bnVsbCYmci5sZW5ndGg+MCYmci5mb3JFYWNoKGZ1bmN0aW9uKEksbyl7dmFyIEI7c3dpdGNoKEkudHlwZSl7Y2FzZSBkLlRleHRTdHJlYW06e2xldCBjPWd0LmVuY29kZShJLmRhdGEuZGF0YSksQz1TKEEsYyxvLDApLGw9e3NpemU6Yy5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTt6KEEsbCxvKTticmVha31jYXNlIGQuSnNvbkNvbXBhdGlibGU6e2xldCBjPWd0LmVuY29kZShKU09OLnN0cmluZ2lmeShJLmRhdGEpKSxDPVMoQSxjLG8sMCksbD17c2l6ZTpjLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O3ooQSxsLG8pO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBjPUkuZGF0YS5kYXRhLEM9UyhBLGMsbywwKSxsPXtzaXplOmMuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07eihBLGwsbyk7YnJlYWt9Y2FzZSBkLlRleHRGaWxlOntBLmZzX3dyaXRlRmlsZShJLmRhdGEucGF0aCxJLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBkLkJpbmFyeUZpbGU6e0EuZnNfd3JpdGVGaWxlKEkuZGF0YS5wYXRoLEkuZGF0YS5kYXRhKTticmVha31jYXNlIGQuSW1hZ2U6e2xldCBjPUkuZGF0YSxDPVMoQSxjLmRhdGEsbywwKSxsPVMoQSxjLmRpcmVjdGlvbixvLDEpLEU9dHlwZW9mKChCPWMubWV0YWRhdGEpPT09bnVsbHx8Qj09PXZvaWQgMD92b2lkIDA6Qi5lbnRyaWVzKTwidSI/SlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShjLm1ldGFkYXRhLmVudHJpZXMoKSkpOiJbXSIsbT17aW1hZ2VUeXBlOmMuaW1hZ2VUeXBlLG5hbWU6Yy5uYW1lLG9yaWdpbjpjLm9yaWdpbixzcGFjaW5nOmMuc3BhY2luZyxkaXJlY3Rpb246YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsc2l6ZTpjLnNpemUsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YCxtZXRhZGF0YTpFfTt6KEEsbSxvKTticmVha31jYXNlIGQuTWVzaDp7bGV0IGM9SS5kYXRhLEM9UyhBLGMucG9pbnRzLG8sMCksbD1TKEEsYy5jZWxscyxvLDEpLEU9UyhBLGMucG9pbnREYXRhLG8sMiksbT1TKEEsYy5jZWxsRGF0YSxvLDMpLGg9e21lc2hUeXBlOmMubWVzaFR5cGUsbmFtZTpjLm5hbWUsbnVtYmVyT2ZQb2ludHM6Yy5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsbnVtYmVyT2ZDZWxsczpjLm51bWJlck9mQ2VsbHMsY2VsbHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsY2VsbEJ1ZmZlclNpemU6Yy5jZWxsQnVmZmVyU2l6ZSxudW1iZXJPZlBvaW50UGl4ZWxzOmMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmMubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bX1gfTt6KEEsaCxvKTticmVha31jYXNlIGQuUG9seURhdGE6e2xldCBjPUkuZGF0YSxDPVMoQSxjLnBvaW50cyxvLDApLGw9UyhBLGMudmVydGljZXMsbywxKSxFPVMoQSxjLmxpbmVzLG8sMiksbT1TKEEsYy5wb2x5Z29ucyxvLDMpLGg9UyhBLGMudHJpYW5nbGVTdHJpcHMsbyw0KSxwPVMoQSxjLnBvaW50RGF0YSxvLDUpLHc9UyhBLGMucG9pbnREYXRhLG8sNiksU0E9e3BvbHlEYXRhVHlwZTpjLnBvbHlEYXRhVHlwZSxuYW1lOmMubmFtZSxudW1iZXJPZlBvaW50czpjLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YCx2ZXJ0aWNlc0J1ZmZlclNpemU6Yy52ZXJ0aWNlc0J1ZmZlclNpemUsdmVydGljZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtsfWAsbGluZXNCdWZmZXJTaXplOmMubGluZXNCdWZmZXJTaXplLGxpbmVzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7RX1gLHBvbHlnb25zQnVmZmVyU2l6ZTpjLnBvbHlnb25zQnVmZmVyU2l6ZSxwb2x5Z29uczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YCx0cmlhbmdsZVN0cmlwc0J1ZmZlclNpemU6Yy50cmlhbmdsZVN0cmlwc0J1ZmZlclNpemUsdHJpYW5nbGVTdHJpcHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtofWAsbnVtYmVyT2ZQb2ludFBpeGVsczpjLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7cH1gLG51bWJlck9mQ2VsbFBpeGVsczpjLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3d9YH07eihBLFNBLG8pO2JyZWFrfWNhc2UgVS5UZXh0OntBLmZzX3dyaXRlRmlsZShJLnBhdGgsSS5kYXRhKTticmVha31jYXNlIFUuQmluYXJ5OntBLmZzX3dyaXRlRmlsZShJLnBhdGgsSS5kYXRhKTticmVha31jYXNlIFUuSW1hZ2U6e2xldCBjPUkuZGF0YSxDPXtpbWFnZVR5cGU6Yy5pbWFnZVR5cGUsbmFtZTpjLm5hbWUsb3JpZ2luOmMub3JpZ2luLHNwYWNpbmc6Yy5zcGFjaW5nLGRpcmVjdGlvbjoiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kaXJlY3Rpb24ucmF3IixzaXplOmMuc2l6ZSxkYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2RhdGEucmF3In07aWYoQS5mc19ta2RpcnMoYCR7SS5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShDKSksYy5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UuZGF0YSBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2RhdGEucmF3YCxuZXcgVWludDhBcnJheShjLmRhdGEuYnVmZmVyKSksQS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgLG5ldyBVaW50OEFycmF5KGMuZGlyZWN0aW9uLmJ1ZmZlcikpO2JyZWFrfWNhc2UgVS5NZXNoOntsZXQgYz1JLmRhdGEsQz17bWVzaFR5cGU6Yy5tZXNoVHlwZSxuYW1lOmMubmFtZSxudW1iZXJPZlBvaW50czpjLm51bWJlck9mUG9pbnRzLHBvaW50czoiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9wb2ludHMucmF3IixudW1iZXJPZlBvaW50UGl4ZWxzOmMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnREYXRhLnJhdyIsbnVtYmVyT2ZDZWxsczpjLm51bWJlck9mQ2VsbHMsY2VsbHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvY2VsbHMucmF3IixudW1iZXJPZkNlbGxQaXhlbHM6Yy5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvY2VsbERhdGEucmF3IixjZWxsQnVmZmVyU2l6ZTpjLmNlbGxCdWZmZXJTaXplfTtpZihBLmZzX21rZGlycyhgJHtJLnBhdGh9L2RhdGFgKSxBLmZzX3dyaXRlRmlsZShgJHtJLnBhdGh9L2luZGV4Lmpzb25gLEpTT04uc3RyaW5naWZ5KEMpKSxDLm51bWJlck9mUG9pbnRzPjApe2lmKGMucG9pbnRzPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke0kucGF0aH0vZGF0YS9wb2ludHMucmF3YCxuZXcgVWludDhBcnJheShjLnBvaW50cy5idWZmZXIpKX1pZihDLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7aWYoYy5wb2ludERhdGE9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLnBvaW50RGF0YSBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL3BvaW50RGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGMucG9pbnREYXRhLmJ1ZmZlcikpfWlmKEMubnVtYmVyT2ZDZWxscz4wKXtpZihjLmNlbGxzPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5jZWxscyBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2NlbGxzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYy5jZWxscy5idWZmZXIpKX1pZihDLm51bWJlck9mQ2VsbFBpeGVscz4wKXtpZihjLmNlbGxEYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5jZWxsRGF0YSBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7SS5wYXRofS9kYXRhL2NlbGxEYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYy5jZWxsRGF0YS5idWZmZXIpKX1icmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBpbnB1dCBJbnRlcmZhY2VUeXBlIil9fSksQS5yZXNldE1vZHVsZVN0ZG91dCgpLEEucmVzZXRNb2R1bGVTdGRlcnIoKTtsZXQgbj1BLnN0YWNrU2F2ZSgpLGk9MDt0cnl7aT1BLmNhbGxNYWluKGUuc2xpY2UoKSl9Y2F0Y2goSSl7dGhyb3cgdHlwZW9mIEk9PSJudW1iZXIiJiYoY29uc29sZS5sb2coIkV4Y2VwdGlvbiB3aGlsZSBydW5uaW5nIHBpcGVsaW5lOiIpLGNvbnNvbGUubG9nKCJzdGRvdXQ6IixBLmdldE1vZHVsZVN0ZG91dCgpKSxjb25zb2xlLmVycm9yKCJzdGRlcnI6IixBLmdldE1vZHVsZVN0ZGVycigpKSx0eXBlb2YgQS5nZXRFeGNlcHRpb25NZXNzYWdlPCJ1Ij9jb25zb2xlLmVycm9yKCJleGNlcHRpb246IixBLmdldEV4Y2VwdGlvbk1lc3NhZ2UoSSkpOmNvbnNvbGUuZXJyb3IoIkJ1aWxkIG1vZHVsZSBpbiBEZWJ1ZyBtb2RlIGZvciBleGNlcHRpb24gbWVzc2FnZSBpbmZvcm1hdGlvbi4iKSksSX1maW5hbGx5e0Euc3RhY2tSZXN0b3JlKG4pfWxldCBhPUEuZ2V0TW9kdWxlU3Rkb3V0KCksZz1BLmdldE1vZHVsZVN0ZGVycigpLGY9W107cmV0dXJuIHQhPW51bGwmJnQubGVuZ3RoPjAmJmk9PT0wJiZ0LmZvckVhY2goZnVuY3Rpb24oSSxvKXtsZXQgQj1udWxsO3N3aXRjaChJLnR5cGUpe2Nhc2UgZC5UZXh0U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxvLDBdKSxsPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG8sMF0pLEU9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEMsbCk7Qj17ZGF0YTpsdC5kZWNvZGUoRSl9O2JyZWFrfWNhc2UgZC5Kc29uQ29tcGF0aWJsZTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbywwXSksbD1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxvLDBdKSxFPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLGwpO0I9SlNPTi5wYXJzZShsdC5kZWNvZGUoRSkpO2JyZWFrfWNhc2UgZC5CaW5hcnlTdHJlYW06e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG8sMF0pLGw9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbywwXSk7Qj17ZGF0YTpjdChBLEMsbCl9O2JyZWFrfWNhc2UgZC5UZXh0RmlsZTp7Qj17cGF0aDpJLmRhdGEucGF0aCxkYXRhOkEuZnNfcmVhZEZpbGUoSS5kYXRhLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pfTticmVha31jYXNlIGQuQmluYXJ5RmlsZTp7Qj17cGF0aDpJLmRhdGEucGF0aCxkYXRhOk0oQSxJLmRhdGEucGF0aCl9O2JyZWFrfWNhc2UgZC5JbWFnZTp7bGV0IEM9cmUoQSxvKTtDLmRhdGE9TihBLG8sMCxDLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKSxDLmRpcmVjdGlvbj1OKEEsbywxLEQuRmxvYXQ2NCksQy5tZXRhZGF0YT1uZXcgTWFwKEMubWV0YWRhdGEpLEI9QzticmVha31jYXNlIGQuTWVzaDp7bGV0IEM9cmUoQSxvKTtDLm51bWJlck9mUG9pbnRzPjA/Qy5wb2ludHM9TihBLG8sMCxDLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSk6Qy5wb2ludHM9YihDLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxscz4wP0MuY2VsbHM9TihBLG8sMSxDLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlKTpDLmNlbGxzPWIoQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZQb2ludFBpeGVscz4wP0MucG9pbnREYXRhPU4oQSxvLDIsQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5wb2ludERhdGE9YihDLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxQaXhlbHM+MD9DLmNlbGxEYXRhPU4oQSxvLDMsQy5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlKTpDLmNlbGxEYXRhPWIoQy5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQj1DO2JyZWFrfWNhc2UgZC5Qb2x5RGF0YTp7bGV0IEM9cmUoQSxvKTtDLm51bWJlck9mUG9pbnRzPjA/Qy5wb2ludHM9TihBLG8sMCxELkZsb2F0MzIpOkMucG9pbnRzPW5ldyBGbG9hdDMyQXJyYXksQy52ZXJ0aWNlc0J1ZmZlclNpemU+MD9DLnZlcnRpY2VzPU4oQSxvLDEsUS5VSW50MzIpOkMudmVydGljZXM9bmV3IFVpbnQzMkFycmF5LEMubGluZXNCdWZmZXJTaXplPjA/Qy5saW5lcz1OKEEsbywyLFEuVUludDMyKTpDLmxpbmVzPW5ldyBVaW50MzJBcnJheSxDLnBvbHlnb25zQnVmZmVyU2l6ZT4wP0MucG9seWdvbnM9TihBLG8sMyxRLlVJbnQzMik6Qy5wb2x5Z29ucz1uZXcgVWludDMyQXJyYXksQy50cmlhbmdsZVN0cmlwc0J1ZmZlclNpemU+MD9DLnRyaWFuZ2xlU3RyaXBzPU4oQSxvLDQsUS5VSW50MzIpOkMudHJpYW5nbGVTdHJpcHM9bmV3IFVpbnQzMkFycmF5LEMubnVtYmVyT2ZQb2ludFBpeGVscz4wP0MucG9pbnREYXRhPU4oQSxvLDUsQy5wb2x5RGF0YVR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPWIoQy5wb2x5RGF0YVR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbFBpeGVscz4wP0MuY2VsbERhdGE9TihBLG8sNixDLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlKTpDLmNlbGxEYXRhPWIoQy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEI9QzticmVha31jYXNlIFUuVGV4dDp7aWYodHlwZW9mIEkucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO0I9QS5mc19yZWFkRmlsZShJLnBhdGgse2VuY29kaW5nOiJ1dGY4In0pO2JyZWFrfWNhc2UgVS5CaW5hcnk6e2lmKHR5cGVvZiBJLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtCPU0oQSxJLnBhdGgpO2JyZWFrfWNhc2UgVS5JbWFnZTp7aWYodHlwZW9mIEkucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO2xldCBDPUEuZnNfcmVhZEZpbGUoYCR7SS5wYXRofS9pbmRleC5qc29uYCx7ZW5jb2Rpbmc6InV0ZjgifSksbD1KU09OLnBhcnNlKEMpLEU9TShBLGAke0kucGF0aH0vZGF0YS9kYXRhLnJhd2ApO2wuZGF0YT1iKGwuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUsRS5idWZmZXIpO2xldCBtPU0oQSxgJHtJLnBhdGh9L2RhdGEvZGlyZWN0aW9uLnJhd2ApO2wuZGlyZWN0aW9uPWIoRC5GbG9hdDY0LG0uYnVmZmVyKSxCPWw7YnJlYWt9Y2FzZSBVLk1lc2g6e2lmKHR5cGVvZiBJLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgQz1BLmZzX3JlYWRGaWxlKGAke0kucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLGw9SlNPTi5wYXJzZShDKTtpZihsLm51bWJlck9mUG9pbnRzPjApe2xldCBFPU0oQSxgJHtJLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2ApO2wucG9pbnRzPWIobC5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsRS5idWZmZXIpfWVsc2UgbC5wb2ludHM9YihsLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKGwubnVtYmVyT2ZQb2ludFBpeGVscz4wKXtsZXQgRT1NKEEsYCR7SS5wYXRofS9kYXRhL3BvaW50RGF0YS5yYXdgKTtsLnBvaW50RGF0YT1iKGwubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsRS5idWZmZXIpfWVsc2UgbC5wb2ludERhdGE9YihsLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYobC5udW1iZXJPZkNlbGxzPjApe2xldCBFPU0oQSxgJHtJLnBhdGh9L2RhdGEvY2VsbHMucmF3YCk7bC5jZWxscz1iKGwubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsRS5idWZmZXIpfWVsc2UgbC5jZWxscz1iKGwubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihsLm51bWJlck9mQ2VsbFBpeGVscz4wKXtsZXQgRT1NKEEsYCR7SS5wYXRofS9kYXRhL2NlbGxEYXRhLnJhd2ApO2wuY2VsbERhdGE9YihsLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsRS5idWZmZXIpfWVsc2UgbC5jZWxsRGF0YT1iKGwubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO0I9bDticmVha31kZWZhdWx0OnRocm93IEVycm9yKCJVbnN1cHBvcnRlZCBvdXRwdXQgSW50ZXJmYWNlVHlwZSIpfWxldCBjPXt0eXBlOkkudHlwZSxkYXRhOkJ9O2YucHVzaChjKX0pLHtyZXR1cm5WYWx1ZTppLHN0ZG91dDphLHN0ZGVycjpnLG91dHB1dHM6Zn19dmFyIEJ0PVZyO3ZhciBuZT1uZXcgTWFwO2FzeW5jIGZ1bmN0aW9uIFpyKEEpe2xldCBlPUEsdD1BO2lmKHR5cGVvZiBBIT0ic3RyaW5nIiYmKGU9bmV3IFVSTChBLmhyZWYpLHQ9ZS5ocmVmKSxuZS5oYXModCkpcmV0dXJuIG5lLmdldCh0KTt7bGV0IHI9YXdhaXQgc3QoQSxZLnBpcGVsaW5lc1VybCk7cmV0dXJuIG5lLnNldCh0LHIpLHJ9fWFzeW5jIGZ1bmN0aW9uIFhyKEEsZSx0LHIsbixpKXt2YXIgYSxnO2lmKCFhd2FpdCBJdCgpKXtsZXQgcD0iV2ViQXNzZW1ibHkgU0lNRCBzdXBwb3J0IGlzIHJlcXVpcmVkIC0tIHBsZWFzZSB1cGRhdGUgeW91ciBicm93c2VyLiI7dGhyb3cgYWxlcnQocCksbmV3IEVycm9yKHApfWlmKEE9PT0hMSl7bGV0IHA9YXdhaXQgWnIoZS50b1N0cmluZygpKTtyZXR1cm4gQnQocCx0LHIsbil9bGV0IGY9QSxJPShhPWk/LnBpcGVsaW5lV29ya2VyVXJsKSE9PW51bGwmJmEhPT12b2lkIDA/YTpudWxsLG89dHlwZW9mIEkhPSJzdHJpbmciJiZ0eXBlb2YgST8uaHJlZjwidSI/SS5ocmVmOkkse3dvcmtlclByb3h5OkIsd29ya2VyOmN9PWF3YWl0IG50KGYsbyk7Zj1jO2xldCBDPVtdO24hPW51bGwmJm4ubGVuZ3RoPjAmJm4uZm9yRWFjaChmdW5jdGlvbihwKXtpZihwLnR5cGU9PT1kLkJpbmFyeVN0cmVhbSl7bGV0IHc9cC5kYXRhLmRhdGE7Qy5wdXNoKHcpfWVsc2UgaWYocC50eXBlPT09ZC5CaW5hcnlGaWxlKXtsZXQgdz1wLmRhdGEuZGF0YTtDLnB1c2godyl9ZWxzZSBpZihwLnR5cGU9PT1kLkltYWdlKXtsZXQgdz1wLmRhdGE7aWYody5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UgZGF0YSBjYW5ub3QgYmUgbnVsbCIpO0MucHVzaCguLi50ZSh3KSl9ZWxzZSBpZihwLnR5cGU9PT1VLkJpbmFyeSlDLnB1c2gocC5kYXRhKTtlbHNlIGlmKHAudHlwZT09PVUuSW1hZ2Upe2xldCB3PXAuZGF0YTtpZih3LmRhdGE9PT1udWxsKXRocm93IEVycm9yKCJpbWFnZSBkYXRhIGNhbm5vdCBiZSBudWxsIik7Qy5wdXNoKC4uLnRlKHcpKX1lbHNlIGlmKHAudHlwZT09PVUuTWVzaCl7bGV0IHc9cC5kYXRhO0MucHVzaCguLi5vdCh3KSl9fSk7bGV0IGw9KGc9aT8ucGlwZWxpbmVCYXNlVXJsKSE9PW51bGwmJmchPT12b2lkIDA/ZzoicGlwZWxpbmVzVXJsIixFPXR5cGVvZiBsIT0ic3RyaW5nIiYmdHlwZW9mIGw/LmhyZWY8InUiP2wuaHJlZjpsLG09biE9bnVsbD9lZShuLENlKEMpKTpudWxsLGg9YXdhaXQgQi5ydW5QaXBlbGluZShZLGUudG9TdHJpbmcoKSxFLHQscixtKTtyZXR1cm57cmV0dXJuVmFsdWU6aC5yZXR1cm5WYWx1ZSxzdGRvdXQ6aC5zdGRvdXQsc3RkZXJyOmguc3RkZXJyLG91dHB1dHM6aC5vdXRwdXRzLHdlYldvcmtlcjpmfX12YXIgYUE9WHI7dmFyIGZ0PXtuYW1lOiJAaXRrLXdhc20vY29tcGFyZS1pbWFnZXMiLHZlcnNpb246IjQuMC4wIixkZXNjcmlwdGlvbjoiQ29tcGFyZSBpbWFnZXMgd2l0aCBhIHRvbGVyYW5jZSBmb3IgcmVncmVzc2lvbiB0ZXN0aW5nLiIsdHlwZToibW9kdWxlIixtb2R1bGU6Ii4vZGlzdC9pbmRleC5qcyIsdHlwZXM6Ii4vZGlzdC9pbmRleC5kLnRzIixleHBvcnRzOnsiLiI6e3R5cGVzOiIuL2Rpc3QvaW5kZXguZC50cyIsYnJvd3NlcjoiLi9kaXN0L2luZGV4LmpzIixub2RlOiIuL2Rpc3QvaW5kZXgtbm9kZS5qcyIsZGVmYXVsdDoiLi9kaXN0L2luZGV4LmpzIn19LHNjcmlwdHM6e3N0YXJ0OiJucG0gcnVuIGNvcHlTaG9lbGFjZUFzc2V0cyAmJiB2aXRlIC1jIGJ1aWxkL3ZpdGUuY29uZmlnLmpzIix0ZXN0OiJucG0gcnVuIHRlc3Q6bm9kZSAmJiBucG0gcnVuIHRlc3Q6YnJvd3NlciIsInRlc3Q6bm9kZSI6ImF2YSB0ZXN0L25vZGUvKi5qcyIsInRlc3Q6YnJvd3NlciI6Im5wbSBydW4gdGVzdDpicm93c2VyOmNocm9tZSAmJiBucG0gcnVuIHRlc3Q6YnJvd3NlcjpmaXJlZm94IiwidGVzdDpicm93c2VyOmZpcmVmb3giOiJzdGFydC1zZXJ2ZXItYW5kLXRlc3Qgc3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTE3MyBjeXByZXNzOnJ1bkZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6Y2hyb21lIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHN0YXJ0IGh0dHAtZ2V0Oi8vbG9jYWxob3N0OjUxNzMgY3lwcmVzczpydW5DaHJvbWUiLCJ0ZXN0OmJyb3dzZXI6ZGVidWciOiJzdGFydC1zZXJ2ZXItYW5kLXRlc3Qgc3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTE3MyBjeXByZXNzOm9wZW4iLCJjeXByZXNzOm9wZW4iOiJucHggY3lwcmVzcyBvcGVuIiwiY3lwcmVzczpydW5DaHJvbWUiOiJucHggY3lwcmVzcyBydW4gLS1icm93c2VyIGNocm9tZSIsImN5cHJlc3M6cnVuRmlyZWZveCI6Im5weCBjeXByZXNzIHJ1biAtLWJyb3dzZXIgZmlyZWZveCIsYnVpbGQ6Im5wbSBydW4gYnVpbGQ6dHNjICYmIG5wbSBydW4gYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZCAmJiBucG0gcnVuIGJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWRNaW4gJiYgbnBtIHJ1biBidWlsZDpkZW1vIiwiYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZCI6ImVzYnVpbGQgLS1sb2FkZXI6Lndvcmtlci5qcz1kYXRhdXJsIC0tYnVuZGxlIC0tZm9ybWF0PWVzbSAtLW91dGZpbGU9Li9kaXN0L2J1bmRsZS9pbmRleC13b3JrZXItZW1iZWRkZWQuanMgLi9zcmMvaW5kZXgtd29ya2VyLWVtYmVkZGVkLnRzIiwiYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZE1pbiI6ImVzYnVpbGQgLS1taW5pZnkgLS1sb2FkZXI6Lndvcmtlci5qcz1kYXRhdXJsIC0tYnVuZGxlIC0tZm9ybWF0PWVzbSAtLW91dGZpbGU9Li9kaXN0L2J1bmRsZS9pbmRleC13b3JrZXItZW1iZWRkZWQubWluLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC5taW4udHMiLCJidWlsZDp0c2MiOiJ0c2MgLS1wcmV0dHkiLGNvcHlTaG9lbGFjZUFzc2V0czoic2h4IG1rZGlyIC1wIHRlc3QvYnJvd3Nlci9kZW1vLWFwcC9wdWJsaWMgJiYgc2h4IGNwIC1yIG5vZGVfbW9kdWxlcy9Ac2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UvZGlzdC9hc3NldHMgdGVzdC9icm93c2VyL2RlbW8tYXBwL3B1YmxpYy8iLCJidWlsZDpkZW1vIjoibnBtIHJ1biBjb3B5U2hvZWxhY2VBc3NldHMgJiYgdml0ZSAtYyBidWlsZC92aXRlLmNvbmZpZy5qcyBidWlsZCJ9LGtleXdvcmRzOlsiaXRrIiwid2FzbSIsIndlYmFzc2VtYmx5Iiwid2FzaSJdLGF1dGhvcjoiIixsaWNlbnNlOiJBcGFjaGUtMi4wIixkZXBlbmRlbmNpZXM6eyJpdGstd2FzbSI6Il4xLjAuMC1iLjE1NCJ9LGRldkRlcGVuZGVuY2llczp7IkBpdGstd2FzbS9pbWFnZS1pbyI6Il4wLjQuMCIsIkBzaG9lbGFjZS1zdHlsZS9zaG9lbGFjZSI6Il4yLjUuMiIsIkB0eXBlcy9ub2RlIjoiXjIwLjIuNSIsYXZhOiJeNS4zLjEiLGN5cHJlc3M6Il4xMi4xNy4yIixzaHg6Il4wLjMuNCIsInN0YXJ0LXNlcnZlci1hbmQtdGVzdCI6Il4yLjAuMiIsdHlwZXNjcmlwdDoiXjUuMC40Iix2aXRlOiJeNC40LjExIiwidml0ZS1wbHVnaW4tc3RhdGljLWNvcHkiOiJeMC4xNy4wIn0scmVwb3NpdG9yeTp7dHlwZToiZ2l0Iix1cmw6Imh0dHBzOi8vZ2l0aHViLmNvbS9JbnNpZ2h0U29mdHdhcmVDb25zb3J0aXVtL2l0ay13YXNtIn19O3ZhciBpZSxBbj1gaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AaXRrLXdhc20vY29tcGFyZS1pbWFnZXNAJHtmdC52ZXJzaW9ufS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gZ3MoQSl7aWU9QX1mdW5jdGlvbiBiQSgpe2lmKHR5cGVvZiBpZTwidSIpcmV0dXJuIGllO2xldCBBPWF0KCk7cmV0dXJuIHR5cGVvZiBBPCJ1Ij9BOkFufXZhciBhZSxlbj1udWxsO2Z1bmN0aW9uIEV0KEEpe2FlPUF9ZnVuY3Rpb24gUXQoKXtpZih0eXBlb2YgYWU8InUiKXJldHVybiBhZTtsZXQgQT1pdCgpO3JldHVybiB0eXBlb2YgQTwidSI/QTplbn1hc3luYyBmdW5jdGlvbiB0bihBLGUsdD17YmFzZWxpbmVJbWFnZXM6W119KXtsZXQgcj1be3R5cGU6ZC5Kc29uQ29tcGF0aWJsZX0se3R5cGU6ZC5JbWFnZX0se3R5cGU6ZC5JbWFnZX1dLG49W3t0eXBlOmQuSW1hZ2UsZGF0YTplfV0saT1bXSxhPSIwIjtpLnB1c2goYSk7bGV0IGc9IjAiO2kucHVzaChnKTtsZXQgZj0iMSI7aS5wdXNoKGYpO2xldCBJPSIyIjtpZihpLnB1c2goSSksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmJhc2VsaW5lSW1hZ2VzPCJ1Iil7aWYodC5iYXNlbGluZUltYWdlcy5sZW5ndGg8MSl0aHJvdyBuZXcgRXJyb3IoJyJiYXNlbGluZS1pbWFnZXMiIG9wdGlvbiBtdXN0IGhhdmUgYSBsZW5ndGggPiAxJyk7aS5wdXNoKCItLWJhc2VsaW5lLWltYWdlcyIpLGF3YWl0IFByb21pc2UuYWxsKHQuYmFzZWxpbmVJbWFnZXMubWFwKGFzeW5jIG09PntsZXQgaD1uLmxlbmd0aC50b1N0cmluZygpO24ucHVzaCh7dHlwZTpkLkltYWdlLGRhdGE6bX0pLGkucHVzaChoKX0pKX10eXBlb2YgdC5kaWZmZXJlbmNlVGhyZXNob2xkPCJ1IiYmaS5wdXNoKCItLWRpZmZlcmVuY2UtdGhyZXNob2xkIix0LmRpZmZlcmVuY2VUaHJlc2hvbGQudG9TdHJpbmcoKSksdHlwZW9mIHQucmFkaXVzVG9sZXJhbmNlPCJ1IiYmaS5wdXNoKCItLXJhZGl1cy10b2xlcmFuY2UiLHQucmFkaXVzVG9sZXJhbmNlLnRvU3RyaW5nKCkpLHR5cGVvZiB0Lm51bWJlck9mUGl4ZWxzVG9sZXJhbmNlPCJ1IiYmaS5wdXNoKCItLW51bWJlci1vZi1waXhlbHMtdG9sZXJhbmNlIix0Lm51bWJlck9mUGl4ZWxzVG9sZXJhbmNlLnRvU3RyaW5nKCkpLHR5cGVvZiB0Lmlnbm9yZUJvdW5kYXJ5UGl4ZWxzPCJ1IiYmdC5pZ25vcmVCb3VuZGFyeVBpeGVscyYmaS5wdXNoKCItLWlnbm9yZS1ib3VuZGFyeS1waXhlbHMiKTtsZXQgbz0iY29tcGFyZS1kb3VibGUtaW1hZ2VzIix7d2ViV29ya2VyOkIscmV0dXJuVmFsdWU6YyxzdGRlcnI6QyxvdXRwdXRzOmx9PWF3YWl0IGFBKEEsbyxpLHIsbix7cGlwZWxpbmVCYXNlVXJsOmJBKCl9KTtpZihjIT09MCl0aHJvdyBuZXcgRXJyb3IoQyk7cmV0dXJue3dlYldvcmtlcjpCLG1ldHJpY3M6bFswXS5kYXRhLGRpZmZlcmVuY2VJbWFnZTpsWzFdLmRhdGEsZGlmZmVyZW5jZVVjaGFyMmRJbWFnZTpsWzJdLmRhdGF9fXZhciBvZT10bjthc3luYyBmdW5jdGlvbiBybihBLGUpe2xldCB0PWU7aWYodC5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSE9PUQuRmxvYXQ2NCl7bGV0IHI7ZS5pbWFnZVR5cGUucGl4ZWxUeXBlIT09Ui5TY2FsYXImJmUuaW1hZ2VUeXBlLnBpeGVsVHlwZSE9PVIuVmFyaWFibGVMZW5ndGhWZWN0b3ImJihyPVIuVmFyaWFibGVMZW5ndGhWZWN0b3IpLHQ9b0EoZSx7Y29tcG9uZW50VHlwZTpELkZsb2F0NjQscGl4ZWxUeXBlOnJ9KX1lbHNlIGlmKGUuaW1hZ2VUeXBlLnBpeGVsVHlwZSE9PVIuU2NhbGFyJiZlLmltYWdlVHlwZS5waXhlbFR5cGUhPT1SLlZhcmlhYmxlTGVuZ3RoVmVjdG9yKXtsZXQgcj1SLlZhcmlhYmxlTGVuZ3RoVmVjdG9yO3Q9b0EoZSx7cGl4ZWxUeXBlOnJ9KX1yZXR1cm4gdC5pbWFnZVR5cGUucGl4ZWxUeXBlPT09Ui5WYXJpYWJsZUxlbmd0aFZlY3RvciYmKHQ9KGF3YWl0IEEodCkpLm1hZ25pdHVkZUltYWdlKSx0fXZhciBzZT1ybjthc3luYyBmdW5jdGlvbiBubihBLGUpe2xldCB0PVt7dHlwZTpkLkltYWdlfV0scj1be3R5cGU6ZC5JbWFnZSxkYXRhOmV9XSxuPVtdLGk9IjAiO24ucHVzaChpKTtsZXQgYT0iMCI7bi5wdXNoKGEpLG4ucHVzaCgiLS1tZW1vcnktaW8iKTtsZXQgZz0idmVjdG9yLW1hZ25pdHVkZSIse3dlYldvcmtlcjpmLHJldHVyblZhbHVlOkksc3RkZXJyOm8sb3V0cHV0czpCfT1hd2FpdCBhQShBLGcsbix0LHIse3BpcGVsaW5lQmFzZVVybDpiQSgpLHBpcGVsaW5lV29ya2VyVXJsOlF0KCl9KTtpZihJIT09MCYmbyE9PSIiKXRocm93IG5ldyBFcnJvcihvKTtyZXR1cm57d2ViV29ya2VyOmYsbWFnbml0dWRlSW1hZ2U6QlswXT8uZGF0YX19dmFyIHV0PW5uO2FzeW5jIGZ1bmN0aW9uIGFuKEEsZSx0PXtiYXNlbGluZUltYWdlczpbXX0pe2FzeW5jIGZ1bmN0aW9uIHIoZyl7bGV0e3dlYldvcmtlcjpmLG1hZ25pdHVkZUltYWdlOkl9PWF3YWl0IHV0KG51bGwsZyk7cmV0dXJuIGY/LnRlcm1pbmF0ZSgpLHttYWduaXR1ZGVJbWFnZTpJfX1sZXQgbj1hd2FpdCBzZShyLGUpLGk9YXdhaXQgUHJvbWlzZS5hbGwodC5iYXNlbGluZUltYWdlcy5tYXAoYXN5bmMgZz0+YXdhaXQgc2UocixnKSkpLGE9ey4uLnR9O3JldHVybiBhLmJhc2VsaW5lSW1hZ2VzPWksb2UoQSxuLGEpfXZhciBvbj1hbjt2YXIgZHQ9J2RhdGE6dGV4dC9qYXZhc2NyaXB0O2NoYXJzZXQ9dXRmLTgsdmFyIGNlPVN5bWJvbCgiQ29tbGluay5wcm94eSIpLEN0PVN5bWJvbCgiQ29tbGluay5lbmRwb2ludCIpLEJ0PVN5bWJvbCgiQ29tbGluay5yZWxlYXNlUHJveHkiKSxNQT1TeW1ib2woIkNvbWxpbmsuZmluYWxpemVyIiksc0E9U3ltYm9sKCJDb21saW5rLnRocm93biIpLGZlPUE9PnR5cGVvZiBBPT0ib2JqZWN0IiYmQSE9PW51bGx8fHR5cGVvZiBBPT0iZnVuY3Rpb24iLFF0PXtjYW5IYW5kbGU6QT0+ZmUoQSkmJkFbY2VdLHNlcmlhbGl6ZShBKXtsZXR7cG9ydDE6ZSxwb3J0Mjp0fT1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIEVBKEEsZSksW3QsW3RdXX0sZGVzZXJpYWxpemUoQSl7cmV0dXJuIEEuc3RhcnQoKSxsdChBKX19LEV0PXtjYW5IYW5kbGU6QT0+ZmUoQSkmJnNBIGluIEEsc2VyaWFsaXplKHt2YWx1ZTpBfSl7bGV0IGU7cmV0dXJuIEEgaW5zdGFuY2VvZiBFcnJvcj9lPXtpc0Vycm9yOiEwLHZhbHVlOnttZXNzYWdlOkEubWVzc2FnZSxuYW1lOkEubmFtZSxzdGFjazpBLnN0YWNrfX06ZT17aXNFcnJvcjohMSx2YWx1ZTpBfSxbZSxbXV19LGRlc2VyaWFsaXplKEEpe3Rocm93IEEuaXNFcnJvcj9PYmplY3QuYXNzaWduKG5ldyBFcnJvcihBLnZhbHVlLm1lc3NhZ2UpLEEudmFsdWUpOkEudmFsdWV9fSxsZT1uZXcgTWFwKFtbInByb3h5IixRdF0sWyJ0aHJvdyIsRXRdXSk7ZnVuY3Rpb24gY3QoQSxlKXtmb3IobGV0IHQgb2YgQSlpZihlPT09dHx8dD09PSIqInx8dCBpbnN0YW5jZW9mIFJlZ0V4cCYmdC50ZXN0KGUpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIEVBKEEsZT1nbG9iYWxUaGlzLHQ9WyIqIl0pe2UuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gSShyKXtpZighcnx8IXIuZGF0YSlyZXR1cm47aWYoIWN0KHQsci5vcmlnaW4pKXtjb25zb2xlLndhcm4oYEludmFsaWQgb3JpZ2luIFwnJHtyLm9yaWdpbn1cJyBmb3IgY29tbGluayBwcm94eWApO3JldHVybn1sZXR7aWQ6aSx0eXBlOmcscGF0aDpufT1PYmplY3QuYXNzaWduKHtwYXRoOltdfSxyLmRhdGEpLEU9KHIuZGF0YS5hcmd1bWVudExpc3R8fFtdKS5tYXAocSksbzt0cnl7bGV0IEI9bi5zbGljZSgwLC0xKS5yZWR1Y2UoKGEsQyk9PmFbQ10sQSksYz1uLnJlZHVjZSgoYSxDKT0+YVtDXSxBKTtzd2l0Y2goZyl7Y2FzZSJHRVQiOm89YzticmVhaztjYXNlIlNFVCI6QltuLnNsaWNlKC0xKVswXV09cShyLmRhdGEudmFsdWUpLG89ITA7YnJlYWs7Y2FzZSJBUFBMWSI6bz1jLmFwcGx5KEIsRSk7YnJlYWs7Y2FzZSJDT05TVFJVQ1QiOntsZXQgYT1uZXcgYyguLi5FKTtvPW10KGEpfWJyZWFrO2Nhc2UiRU5EUE9JTlQiOntsZXR7cG9ydDE6YSxwb3J0MjpDfT1uZXcgTWVzc2FnZUNoYW5uZWw7RUEoQSxDKSxvPUhBKGEsW2FdKX1icmVhaztjYXNlIlJFTEVBU0UiOm89dm9pZCAwO2JyZWFrO2RlZmF1bHQ6cmV0dXJufX1jYXRjaChCKXtvPXt2YWx1ZTpCLFtzQV06MH19UHJvbWlzZS5yZXNvbHZlKG8pLmNhdGNoKEI9Pih7dmFsdWU6Qixbc0FdOjB9KSkudGhlbihCPT57bGV0W2MsYV09UUEoQik7ZS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sYykse2lkOml9KSxhKSxnPT09IlJFTEVBU0UiJiYoZS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixJKSx1ZShlKSxNQSBpbiBBJiZ0eXBlb2YgQVtNQV09PSJmdW5jdGlvbiImJkFbTUFdKCkpfSkuY2F0Y2goQj0+e2xldFtjLGFdPVFBKHt2YWx1ZTpuZXcgVHlwZUVycm9yKCJVbnNlcmlhbGl6YWJsZSByZXR1cm4gdmFsdWUiKSxbc0FdOjB9KTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLGEpfSl9KSxlLnN0YXJ0JiZlLnN0YXJ0KCl9ZnVuY3Rpb24gZnQoQSl7cmV0dXJuIEEuY29uc3RydWN0b3IubmFtZT09PSJNZXNzYWdlUG9ydCJ9ZnVuY3Rpb24gdWUoQSl7ZnQoQSkmJkEuY2xvc2UoKX1mdW5jdGlvbiBsdChBLGUpe3JldHVybiBiQShBLFtdLGUpfWZ1bmN0aW9uIGFBKEEpe2lmKEEpdGhyb3cgbmV3IEVycm9yKCJQcm94eSBoYXMgYmVlbiByZWxlYXNlZCBhbmQgaXMgbm90IHVzZWFibGUiKX1mdW5jdGlvbiBoZShBKXtyZXR1cm4geChBLHt0eXBlOiJSRUxFQVNFIn0pLnRoZW4oKCk9Pnt1ZShBKX0pfXZhciBDQT1uZXcgV2Vha01hcCxCQT0iRmluYWxpemF0aW9uUmVnaXN0cnkiaW4gZ2xvYmFsVGhpcyYmbmV3IEZpbmFsaXphdGlvblJlZ2lzdHJ5KEE9PntsZXQgZT0oQ0EuZ2V0KEEpfHwwKS0xO0NBLnNldChBLGUpLGU9PT0wJiZoZShBKX0pO2Z1bmN0aW9uIHV0KEEsZSl7bGV0IHQ9KENBLmdldChlKXx8MCkrMTtDQS5zZXQoZSx0KSxCQSYmQkEucmVnaXN0ZXIoQSxlLEEpfWZ1bmN0aW9uIGh0KEEpe0JBJiZCQS51bnJlZ2lzdGVyKEEpfWZ1bmN0aW9uIGJBKEEsZT1bXSx0PWZ1bmN0aW9uKCl7fSl7bGV0IEk9ITEscj1uZXcgUHJveHkodCx7Z2V0KGksZyl7aWYoYUEoSSksZz09PUJ0KXJldHVybigpPT57aHQociksaGUoQSksST0hMH07aWYoZz09PSJ0aGVuIil7aWYoZS5sZW5ndGg9PT0wKXJldHVybnt0aGVuOigpPT5yfTtsZXQgbj14KEEse3R5cGU6IkdFVCIscGF0aDplLm1hcChFPT5FLnRvU3RyaW5nKCkpfSkudGhlbihxKTtyZXR1cm4gbi50aGVuLmJpbmQobil9cmV0dXJuIGJBKEEsWy4uLmUsZ10pfSxzZXQoaSxnLG4pe2FBKEkpO2xldFtFLG9dPVFBKG4pO3JldHVybiB4KEEse3R5cGU6IlNFVCIscGF0aDpbLi4uZSxnXS5tYXAoQj0+Qi50b1N0cmluZygpKSx2YWx1ZTpFfSxvKS50aGVuKHEpfSxhcHBseShpLGcsbil7YUEoSSk7bGV0IEU9ZVtlLmxlbmd0aC0xXTtpZihFPT09Q3QpcmV0dXJuIHgoQSx7dHlwZToiRU5EUE9JTlQifSkudGhlbihxKTtpZihFPT09ImJpbmQiKXJldHVybiBiQShBLGUuc2xpY2UoMCwtMSkpO2xldFtvLEJdPUVlKG4pO3JldHVybiB4KEEse3R5cGU6IkFQUExZIixwYXRoOmUubWFwKGM9PmMudG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Om99LEIpLnRoZW4ocSl9LGNvbnN0cnVjdChpLGcpe2FBKEkpO2xldFtuLEVdPUVlKGcpO3JldHVybiB4KEEse3R5cGU6IkNPTlNUUlVDVCIscGF0aDplLm1hcChvPT5vLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpufSxFKS50aGVuKHEpfX0pO3JldHVybiB1dChyLEEpLHJ9ZnVuY3Rpb24gZHQoQSl7cmV0dXJuIEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoW10sQSl9ZnVuY3Rpb24gRWUoQSl7bGV0IGU9QS5tYXAoUUEpO3JldHVybltlLm1hcCh0PT50WzBdKSxkdChlLm1hcCh0PT50WzFdKSldfXZhciBkZT1uZXcgV2Vha01hcDtmdW5jdGlvbiBIQShBLGUpe3JldHVybiBkZS5zZXQoQSxlKSxBfWZ1bmN0aW9uIG10KEEpe3JldHVybiBPYmplY3QuYXNzaWduKEEse1tjZV06ITB9KX1mdW5jdGlvbiBRQShBKXtmb3IobGV0W2UsdF1vZiBsZSlpZih0LmNhbkhhbmRsZShBKSl7bGV0W0kscl09dC5zZXJpYWxpemUoQSk7cmV0dXJuW3t0eXBlOiJIQU5ETEVSIixuYW1lOmUsdmFsdWU6SX0scl19cmV0dXJuW3t0eXBlOiJSQVciLHZhbHVlOkF9LGRlLmdldChBKXx8W11dfWZ1bmN0aW9uIHEoQSl7c3dpdGNoKEEudHlwZSl7Y2FzZSJIQU5ETEVSIjpyZXR1cm4gbGUuZ2V0KEEubmFtZSkuZGVzZXJpYWxpemUoQS52YWx1ZSk7Y2FzZSJSQVciOnJldHVybiBBLnZhbHVlfX1mdW5jdGlvbiB4KEEsZSx0KXtyZXR1cm4gbmV3IFByb21pc2UoST0+e2xldCByPUR0KCk7QS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBpKGcpeyFnLmRhdGF8fCFnLmRhdGEuaWR8fGcuZGF0YS5pZCE9PXJ8fChBLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGkpLEkoZy5kYXRhKSl9KSxBLnN0YXJ0JiZBLnN0YXJ0KCksQS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKHtpZDpyfSxlKSx0KX0pfWZ1bmN0aW9uIER0KCl7cmV0dXJuIG5ldyBBcnJheSg0KS5maWxsKDApLm1hcCgoKT0+TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpKk51bWJlci5NQVhfU0FGRV9JTlRFR0VSKS50b1N0cmluZygxNikpLmpvaW4oIi0iKX1mdW5jdGlvbiBYKEEsZSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIEEuYXBwbHkoZSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6eXR9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOlRBfT1PYmplY3QsZkE9KEE9PmU9PntsZXQgdD15dC5jYWxsKGUpO3JldHVybiBBW3RdfHwoQVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSksVT1BPT4oQT1BLnRvTG93ZXJDYXNlKCksZT0+ZkEoZSk9PT1BKSxsQT1BPT5lPT50eXBlb2YgZT09PUEse2lzQXJyYXk6UH09QXJyYXksdj1sQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24gd3QoQSl7cmV0dXJuIEEhPT1udWxsJiYhdihBKSYmQS5jb25zdHJ1Y3RvciE9PW51bGwmJiF2KEEuY29uc3RydWN0b3IpJiZSKEEuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZBLmNvbnN0cnVjdG9yLmlzQnVmZmVyKEEpfXZhciB3ZT1VKCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIHB0KEEpe2xldCBlO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/ZT1BcnJheUJ1ZmZlci5pc1ZpZXcoQSk6ZT1BJiZBLmJ1ZmZlciYmd2UoQS5idWZmZXIpLGV9dmFyIEZ0PWxBKCJzdHJpbmciKSxSPWxBKCJmdW5jdGlvbiIpLHBlPWxBKCJudW1iZXIiKSx1QT1BPT5BIT09bnVsbCYmdHlwZW9mIEE9PSJvYmplY3QiLFN0PUE9PkE9PT0hMHx8QT09PSExLGNBPUE9PntpZihmQShBKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBlPVRBKEEpO3JldHVybihlPT09bnVsbHx8ZT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihlKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBBKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gQSl9LE50PVUoIkRhdGUiKSxSdD1VKCJGaWxlIiksR3Q9VSgiQmxvYiIpLFV0PVUoIkZpbGVMaXN0Iiksa3Q9QT0+dUEoQSkmJlIoQS5waXBlKSxMdD1BPT57bGV0IGU7cmV0dXJuIEEmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJkEgaW5zdGFuY2VvZiBGb3JtRGF0YXx8UihBLmFwcGVuZCkmJigoZT1mQShBKSk9PT0iZm9ybWRhdGEifHxlPT09Im9iamVjdCImJlIoQS50b1N0cmluZykmJkEudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sT3Q9VSgiVVJMU2VhcmNoUGFyYW1zIiksSnQ9QT0+QS50cmltP0EudHJpbSgpOkEucmVwbGFjZSgvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2csIiIpO2Z1bmN0aW9uICQoQSxlLHthbGxPd25LZXlzOnQ9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgSSxyO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxQKEEpKWZvcihJPTAscj1BLmxlbmd0aDtJPHI7SSsrKWUuY2FsbChudWxsLEFbSV0sSSxBKTtlbHNle2xldCBpPXQ/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSk6T2JqZWN0LmtleXMoQSksZz1pLmxlbmd0aCxuO2ZvcihJPTA7STxnO0krKyluPWlbSV0sZS5jYWxsKG51bGwsQVtuXSxuLEEpfX1mdW5jdGlvbiBGZShBLGUpe2U9ZS50b0xvd2VyQ2FzZSgpO2xldCB0PU9iamVjdC5rZXlzKEEpLEk9dC5sZW5ndGgscjtmb3IoO0ktLSA+MDspaWYocj10W0ldLGU9PT1yLnRvTG93ZXJDYXNlKCkpcmV0dXJuIHI7cmV0dXJuIG51bGx9dmFyIFNlPSgoKT0+dHlwZW9mIGdsb2JhbFRoaXM8InUiP2dsb2JhbFRoaXM6dHlwZW9mIHNlbGY8InUiP3NlbGY6dHlwZW9mIHdpbmRvdzwidSI/d2luZG93Omdsb2JhbCkoKSxOZT1BPT4hdihBKSYmQSE9PVNlO2Z1bmN0aW9uIHFBKCl7bGV0e2Nhc2VsZXNzOkF9PU5lKHRoaXMpJiZ0aGlzfHx7fSxlPXt9LHQ9KEkscik9PntsZXQgaT1BJiZGZShlLHIpfHxyO2NBKGVbaV0pJiZjQShJKT9lW2ldPXFBKGVbaV0sSSk6Y0EoSSk/ZVtpXT1xQSh7fSxJKTpQKEkpP2VbaV09SS5zbGljZSgpOmVbaV09SX07Zm9yKGxldCBJPTAscj1hcmd1bWVudHMubGVuZ3RoO0k8cjtJKyspYXJndW1lbnRzW0ldJiYkKGFyZ3VtZW50c1tJXSx0KTtyZXR1cm4gZX12YXIgTXQ9KEEsZSx0LHthbGxPd25LZXlzOkl9PXt9KT0+KCQoZSwocixpKT0+e3QmJlIocik/QVtpXT1YKHIsdCk6QVtpXT1yfSx7YWxsT3duS2V5czpJfSksQSksYnQ9QT0+KEEuY2hhckNvZGVBdCgwKT09PTY1Mjc5JiYoQT1BLnNsaWNlKDEpKSxBKSxIdD0oQSxlLHQsSSk9PntBLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKGUucHJvdG90eXBlLEkpLEEucHJvdG90eXBlLmNvbnN0cnVjdG9yPUEsT2JqZWN0LmRlZmluZVByb3BlcnR5KEEsInN1cGVyIix7dmFsdWU6ZS5wcm90b3R5cGV9KSx0JiZPYmplY3QuYXNzaWduKEEucHJvdG90eXBlLHQpfSxZdD0oQSxlLHQsSSk9PntsZXQgcixpLGcsbj17fTtpZihlPWV8fHt9LEE9PW51bGwpcmV0dXJuIGU7ZG97Zm9yKHI9T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSksaT1yLmxlbmd0aDtpLS0gPjA7KWc9cltpXSwoIUl8fEkoZyxBLGUpKSYmIW5bZ10mJihlW2ddPUFbZ10sbltnXT0hMCk7QT10IT09ITEmJlRBKEEpfXdoaWxlKEEmJighdHx8dChBLGUpKSYmQSE9PU9iamVjdC5wcm90b3R5cGUpO3JldHVybiBlfSxxdD0oQSxlLHQpPT57QT1TdHJpbmcoQSksKHQ9PT12b2lkIDB8fHQ+QS5sZW5ndGgpJiYodD1BLmxlbmd0aCksdC09ZS5sZW5ndGg7bGV0IEk9QS5pbmRleE9mKGUsdCk7cmV0dXJuIEkhPT0tMSYmST09PXR9LFR0PUE9PntpZighQSlyZXR1cm4gbnVsbDtpZihQKEEpKXJldHVybiBBO2xldCBlPUEubGVuZ3RoO2lmKCFwZShlKSlyZXR1cm4gbnVsbDtsZXQgdD1uZXcgQXJyYXkoZSk7Zm9yKDtlLS0gPjA7KXRbZV09QVtlXTtyZXR1cm4gdH0sS3Q9KEE9PmU9PkEmJmUgaW5zdGFuY2VvZiBBKSh0eXBlb2YgVWludDhBcnJheTwidSImJlRBKFVpbnQ4QXJyYXkpKSx4dD0oQSxlKT0+e2xldCBJPShBJiZBW1N5bWJvbC5pdGVyYXRvcl0pLmNhbGwoQSkscjtmb3IoOyhyPUkubmV4dCgpKSYmIXIuZG9uZTspe2xldCBpPXIudmFsdWU7ZS5jYWxsKEEsaVswXSxpWzFdKX19LFB0PShBLGUpPT57bGV0IHQsST1bXTtmb3IoOyh0PUEuZXhlYyhlKSkhPT1udWxsOylJLnB1c2godCk7cmV0dXJuIEl9LFd0PVUoIkhUTUxGb3JtRWxlbWVudCIpLGp0PUE9PkEudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bLV9cXHNdKFthLXpcXGRdKShcXHcqKS9nLGZ1bmN0aW9uKHQsSSxyKXtyZXR1cm4gSS50b1VwcGVyQ2FzZSgpK3J9KSxEZT0oKHtoYXNPd25Qcm9wZXJ0eTpBfSk9PihlLHQpPT5BLmNhbGwoZSx0KSkoT2JqZWN0LnByb3RvdHlwZSksWnQ9VSgiUmVnRXhwIiksUmU9KEEsZSk9PntsZXQgdD1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyhBKSxJPXt9OyQodCwocixpKT0+e2UocixpLEEpIT09ITEmJihJW2ldPXIpfSksT2JqZWN0LmRlZmluZVByb3BlcnRpZXMoQSxJKX0sX3Q9QT0+e1JlKEEsKGUsdCk9PntpZihSKEEpJiZbImFyZ3VtZW50cyIsImNhbGxlciIsImNhbGxlZSJdLmluZGV4T2YodCkhPT0tMSlyZXR1cm4hMTtsZXQgST1BW3RdO2lmKFIoSSkpe2lmKGUuZW51bWVyYWJsZT0hMSwid3JpdGFibGUiaW4gZSl7ZS53cml0YWJsZT0hMTtyZXR1cm59ZS5zZXR8fChlLnNldD0oKT0+e3Rocm93IEVycm9yKCJDYW4gbm90IHJld3JpdGUgcmVhZC1vbmx5IG1ldGhvZCBcJyIrdCsiXCciKX0pfX0pfSxWdD0oQSxlKT0+e2xldCB0PXt9LEk9cj0+e3IuZm9yRWFjaChpPT57dFtpXT0hMH0pfTtyZXR1cm4gUChBKT9JKEEpOkkoU3RyaW5nKEEpLnNwbGl0KGUpKSx0fSx6dD0oKT0+e30sWHQ9KEEsZSk9PihBPStBLE51bWJlci5pc0Zpbml0ZShBKT9BOmUpLFlBPSJhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5eiIseWU9IjAxMjM0NTY3ODkiLEdlPXtESUdJVDp5ZSxBTFBIQTpZQSxBTFBIQV9ESUdJVDpZQStZQS50b1VwcGVyQ2FzZSgpK3llfSx2dD0oQT0xNixlPUdlLkFMUEhBX0RJR0lUKT0+e2xldCB0PSIiLHtsZW5ndGg6SX09ZTtmb3IoO0EtLTspdCs9ZVtNYXRoLnJhbmRvbSgpKkl8MF07cmV0dXJuIHR9O2Z1bmN0aW9uICR0KEEpe3JldHVybiEhKEEmJlIoQS5hcHBlbmQpJiZBW1N5bWJvbC50b1N0cmluZ1RhZ109PT0iRm9ybURhdGEiJiZBW1N5bWJvbC5pdGVyYXRvcl0pfXZhciBBST1BPT57bGV0IGU9bmV3IEFycmF5KDEwKSx0PShJLHIpPT57aWYodUEoSSkpe2lmKGUuaW5kZXhPZihJKT49MClyZXR1cm47aWYoISgidG9KU09OImluIEkpKXtlW3JdPUk7bGV0IGk9UChJKT9bXTp7fTtyZXR1cm4gJChJLChnLG4pPT57bGV0IEU9dChnLHIrMSk7IXYoRSkmJihpW25dPUUpfSksZVtyXT12b2lkIDAsaX19cmV0dXJuIEl9O3JldHVybiB0KEEsMCl9LGVJPVUoIkFzeW5jRnVuY3Rpb24iKSx0ST1BPT5BJiYodUEoQSl8fFIoQSkpJiZSKEEudGhlbikmJlIoQS5jYXRjaCkscz17aXNBcnJheTpQLGlzQXJyYXlCdWZmZXI6d2UsaXNCdWZmZXI6d3QsaXNGb3JtRGF0YTpMdCxpc0FycmF5QnVmZmVyVmlldzpwdCxpc1N0cmluZzpGdCxpc051bWJlcjpwZSxpc0Jvb2xlYW46U3QsaXNPYmplY3Q6dUEsaXNQbGFpbk9iamVjdDpjQSxpc1VuZGVmaW5lZDp2LGlzRGF0ZTpOdCxpc0ZpbGU6UnQsaXNCbG9iOkd0LGlzUmVnRXhwOlp0LGlzRnVuY3Rpb246Uixpc1N0cmVhbTprdCxpc1VSTFNlYXJjaFBhcmFtczpPdCxpc1R5cGVkQXJyYXk6S3QsaXNGaWxlTGlzdDpVdCxmb3JFYWNoOiQsbWVyZ2U6cUEsZXh0ZW5kOk10LHRyaW06SnQsc3RyaXBCT006YnQsaW5oZXJpdHM6SHQsdG9GbGF0T2JqZWN0Oll0LGtpbmRPZjpmQSxraW5kT2ZUZXN0OlUsZW5kc1dpdGg6cXQsdG9BcnJheTpUdCxmb3JFYWNoRW50cnk6eHQsbWF0Y2hBbGw6UHQsaXNIVE1MRm9ybTpXdCxoYXNPd25Qcm9wZXJ0eTpEZSxoYXNPd25Qcm9wOkRlLHJlZHVjZURlc2NyaXB0b3JzOlJlLGZyZWV6ZU1ldGhvZHM6X3QsdG9PYmplY3RTZXQ6VnQsdG9DYW1lbENhc2U6anQsbm9vcDp6dCx0b0Zpbml0ZU51bWJlcjpYdCxmaW5kS2V5OkZlLGdsb2JhbDpTZSxpc0NvbnRleHREZWZpbmVkOk5lLEFMUEhBQkVUOkdlLGdlbmVyYXRlU3RyaW5nOnZ0LGlzU3BlY0NvbXBsaWFudEZvcm06JHQsdG9KU09OT2JqZWN0OkFJLGlzQXN5bmNGbjplSSxpc1RoZW5hYmxlOnRJfTtmdW5jdGlvbiBXKEEsZSx0LEkscil7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPUEsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixlJiYodGhpcy5jb2RlPWUpLHQmJih0aGlzLmNvbmZpZz10KSxJJiYodGhpcy5yZXF1ZXN0PUkpLHImJih0aGlzLnJlc3BvbnNlPXIpfXMuaW5oZXJpdHMoVyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOnMudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIFVlPVcucHJvdG90eXBlLGtlPXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goQT0+e2tlW0FdPXt2YWx1ZTpBfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFcsa2UpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShVZSwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtXLmZyb209KEEsZSx0LEkscixpKT0+e2xldCBnPU9iamVjdC5jcmVhdGUoVWUpO3JldHVybiBzLnRvRmxhdE9iamVjdChBLGcsZnVuY3Rpb24oRSl7cmV0dXJuIEUhPT1FcnJvci5wcm90b3R5cGV9LG49Pm4hPT0iaXNBeGlvc0Vycm9yIiksVy5jYWxsKGcsQS5tZXNzYWdlLGUsdCxJLHIpLGcuY2F1c2U9QSxnLm5hbWU9QS5uYW1lLGkmJk9iamVjdC5hc3NpZ24oZyxpKSxnfTt2YXIgbD1XO3ZhciBoQT1udWxsO2Z1bmN0aW9uIEtBKEEpe3JldHVybiBzLmlzUGxhaW5PYmplY3QoQSl8fHMuaXNBcnJheShBKX1mdW5jdGlvbiBPZShBKXtyZXR1cm4gcy5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiBMZShBLGUsdCl7cmV0dXJuIEE/QS5jb25jYXQoZSkubWFwKGZ1bmN0aW9uKHIsaSl7cmV0dXJuIHI9T2UociksIXQmJmk/IlsiK3IrIl0iOnJ9KS5qb2luKHQ/Ii4iOiIiKTplfWZ1bmN0aW9uIElJKEEpe3JldHVybiBzLmlzQXJyYXkoQSkmJiFBLnNvbWUoS0EpfXZhciByST1zLnRvRmxhdE9iamVjdChzLHt9LG51bGwsZnVuY3Rpb24oZSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KGUpfSk7ZnVuY3Rpb24gaUkoQSxlLHQpe2lmKCFzLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO2U9ZXx8bmV3KGhBfHxGb3JtRGF0YSksdD1zLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oZixtKXtyZXR1cm4hcy5pc1VuZGVmaW5lZChtW2ZdKX0pO2xldCBJPXQubWV0YVRva2VucyxyPXQudmlzaXRvcnx8QixpPXQuZG90cyxnPXQuaW5kZXhlcyxFPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJnMuaXNTcGVjQ29tcGxpYW50Rm9ybShlKTtpZighcy5pc0Z1bmN0aW9uKHIpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gbyhRKXtpZihRPT09bnVsbClyZXR1cm4iIjtpZihzLmlzRGF0ZShRKSlyZXR1cm4gUS50b0lTT1N0cmluZygpO2lmKCFFJiZzLmlzQmxvYihRKSl0aHJvdyBuZXcgbCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gcy5pc0FycmF5QnVmZmVyKFEpfHxzLmlzVHlwZWRBcnJheShRKT9FJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbUV0pOkJ1ZmZlci5mcm9tKFEpOlF9ZnVuY3Rpb24gQihRLGYsbSl7bGV0IHc9UTtpZihRJiYhbSYmdHlwZW9mIFE9PSJvYmplY3QiKXtpZihzLmVuZHNXaXRoKGYsInt9IikpZj1JP2Y6Zi5zbGljZSgwLC0yKSxRPUpTT04uc3RyaW5naWZ5KFEpO2Vsc2UgaWYocy5pc0FycmF5KFEpJiZJSShRKXx8KHMuaXNGaWxlTGlzdChRKXx8cy5lbmRzV2l0aChmLCJbXSIpKSYmKHc9cy50b0FycmF5KFEpKSlyZXR1cm4gZj1PZShmKSx3LmZvckVhY2goZnVuY3Rpb24oSyxKQSl7IShzLmlzVW5kZWZpbmVkKEspfHxLPT09bnVsbCkmJmUuYXBwZW5kKGc9PT0hMD9MZShbZl0sSkEsaSk6Zz09PW51bGw/ZjpmKyJbXSIsbyhLKSl9KSwhMX1yZXR1cm4gS0EoUSk/ITA6KGUuYXBwZW5kKExlKG0sZixpKSxvKFEpKSwhMSl9bGV0IGM9W10sYT1PYmplY3QuYXNzaWduKHJJLHtkZWZhdWx0VmlzaXRvcjpCLGNvbnZlcnRWYWx1ZTpvLGlzVmlzaXRhYmxlOktBfSk7ZnVuY3Rpb24gQyhRLGYpe2lmKCFzLmlzVW5kZWZpbmVkKFEpKXtpZihjLmluZGV4T2YoUSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrZi5qb2luKCIuIikpO2MucHVzaChRKSxzLmZvckVhY2goUSxmdW5jdGlvbih3LE8peyghKHMuaXNVbmRlZmluZWQodyl8fHc9PT1udWxsKSYmci5jYWxsKGUsdyxzLmlzU3RyaW5nKE8pP08udHJpbSgpOk8sZixhKSk9PT0hMCYmQyh3LGY/Zi5jb25jYXQoTyk6W09dKX0pLGMucG9wKCl9fWlmKCFzLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gQyhBKSxlfXZhciBKPWlJO2Z1bmN0aW9uIEplKEEpe2xldCBlPXsiISI6IiUyNTIxIiwiXCciOiIlMjUyNyIsIigiOiIlMjUyOCIsIikiOiIlMjUyOSIsIn4iOiIlMjU3RSIsIiUyNTIwIjoiKyIsIiUyNTAwIjoiXFwwIn07cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC9bIVwnKCl+XXwlMjUyMHwlMjUwMC9nLGZ1bmN0aW9uKEkpe3JldHVybiBlW0ldfSl9ZnVuY3Rpb24gTWUoQSxlKXt0aGlzLl9wYWlycz1bXSxBJiZKKEEsdGhpcyxlKX12YXIgYmU9TWUucHJvdG90eXBlO2JlLmFwcGVuZD1mdW5jdGlvbihlLHQpe3RoaXMuX3BhaXJzLnB1c2goW2UsdF0pfTtiZS50b1N0cmluZz1mdW5jdGlvbihlKXtsZXQgdD1lP2Z1bmN0aW9uKEkpe3JldHVybiBlLmNhbGwodGhpcyxJLEplKX06SmU7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihyKXtyZXR1cm4gdChyWzBdKSsiPSIrdChyWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIGRBPU1lO2Z1bmN0aW9uIGdJKEEpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvJTI1M0EvZ2ksIjoiKS5yZXBsYWNlKC8lMjUyNC9nLCIkIikucmVwbGFjZSgvJTI1MkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjUyMC9nLCIrIikucmVwbGFjZSgvJTI1NUIvZ2ksIlsiKS5yZXBsYWNlKC8lMjU1RC9naSwiXSIpfWZ1bmN0aW9uIEFBKEEsZSx0KXtpZighZSlyZXR1cm4gQTtsZXQgST10JiZ0LmVuY29kZXx8Z0kscj10JiZ0LnNlcmlhbGl6ZSxpO2lmKHI/aT1yKGUsdCk6aT1zLmlzVVJMU2VhcmNoUGFyYW1zKGUpP2UudG9TdHJpbmcoKTpuZXcgZEEoZSx0KS50b1N0cmluZyhJKSxpKXtsZXQgZz1BLmluZGV4T2YoIiUyMyIpO2chPT0tMSYmKEE9QS5zbGljZSgwLGcpKSxBKz0oQS5pbmRleE9mKCI/Iik9PT0tMT8iPyI6IiYiKStpfXJldHVybiBBfXZhciB4QT1jbGFzc3tjb25zdHJ1Y3Rvcigpe3RoaXMuaGFuZGxlcnM9W119dXNlKGUsdCxJKXtyZXR1cm4gdGhpcy5oYW5kbGVycy5wdXNoKHtmdWxmaWxsZWQ6ZSxyZWplY3RlZDp0LHN5bmNocm9ub3VzOkk/SS5zeW5jaHJvbm91czohMSxydW5XaGVuOkk/SS5ydW5XaGVuOm51bGx9KSx0aGlzLmhhbmRsZXJzLmxlbmd0aC0xfWVqZWN0KGUpe3RoaXMuaGFuZGxlcnNbZV0mJih0aGlzLmhhbmRsZXJzW2VdPW51bGwpfWNsZWFyKCl7dGhpcy5oYW5kbGVycyYmKHRoaXMuaGFuZGxlcnM9W10pfWZvckVhY2goZSl7cy5mb3JFYWNoKHRoaXMuaGFuZGxlcnMsZnVuY3Rpb24oSSl7SSE9PW51bGwmJmUoSSl9KX19LFBBPXhBO3ZhciBtQT17c2lsZW50SlNPTlBhcnNpbmc6ITAsZm9yY2VkSlNPTlBhcnNpbmc6ITAsY2xhcmlmeVRpbWVvdXRFcnJvcjohMX07dmFyIEhlPXR5cGVvZiBVUkxTZWFyY2hQYXJhbXM8InUiP1VSTFNlYXJjaFBhcmFtczpkQTt2YXIgWWU9dHlwZW9mIEZvcm1EYXRhPCJ1Ij9Gb3JtRGF0YTpudWxsO3ZhciBxZT10eXBlb2YgQmxvYjwidSI/QmxvYjpudWxsO3ZhciBvST0oKCk9PntsZXQgQTtyZXR1cm4gdHlwZW9mIG5hdmlnYXRvcjwidSImJigoQT1uYXZpZ2F0b3IucHJvZHVjdCk9PT0iUmVhY3ROYXRpdmUifHxBPT09Ik5hdGl2ZVNjcmlwdCJ8fEE9PT0iTlMiKT8hMTp0eXBlb2Ygd2luZG93PCJ1IiYmdHlwZW9mIGRvY3VtZW50PCJ1In0pKCksbkk9KCgpPT50eXBlb2YgV29ya2VyR2xvYmFsU2NvcGU8InUiJiZzZWxmIGluc3RhbmNlb2YgV29ya2VyR2xvYmFsU2NvcGUmJnR5cGVvZiBzZWxmLmltcG9ydFNjcmlwdHM9PSJmdW5jdGlvbiIpKCksRD17aXNCcm93c2VyOiEwLGNsYXNzZXM6e1VSTFNlYXJjaFBhcmFtczpIZSxGb3JtRGF0YTpZZSxCbG9iOnFlfSxpc1N0YW5kYXJkQnJvd3NlckVudjpvSSxpc1N0YW5kYXJkQnJvd3NlcldlYldvcmtlckVudjpuSSxwcm90b2NvbHM6WyJodHRwIiwiaHR0cHMiLCJmaWxlIiwiYmxvYiIsInVybCIsImRhdGEiXX07ZnVuY3Rpb24gV0EoQSxlKXtyZXR1cm4gSihBLG5ldyBELmNsYXNzZXMuVVJMU2VhcmNoUGFyYW1zLE9iamVjdC5hc3NpZ24oe3Zpc2l0b3I6ZnVuY3Rpb24odCxJLHIsaSl7cmV0dXJuIEQuaXNOb2RlJiZzLmlzQnVmZmVyKHQpPyh0aGlzLmFwcGVuZChJLHQudG9TdHJpbmcoImJhc2U2NCIpKSwhMSk6aS5kZWZhdWx0VmlzaXRvci5hcHBseSh0aGlzLGFyZ3VtZW50cyl9fSxlKSl9ZnVuY3Rpb24gYUkoQSl7cmV0dXJuIHMubWF0Y2hBbGwoL1xcdyt8XFxbKFxcdyopXS9nLEEpLm1hcChlPT5lWzBdPT09IltdIj8iIjplWzFdfHxlWzBdKX1mdW5jdGlvbiBzSShBKXtsZXQgZT17fSx0PU9iamVjdC5rZXlzKEEpLEkscj10Lmxlbmd0aCxpO2ZvcihJPTA7STxyO0krKylpPXRbSV0sZVtpXT1BW2ldO3JldHVybiBlfWZ1bmN0aW9uIENJKEEpe2Z1bmN0aW9uIGUodCxJLHIsaSl7bGV0IGc9dFtpKytdLG49TnVtYmVyLmlzRmluaXRlKCtnKSxFPWk+PXQubGVuZ3RoO3JldHVybiBnPSFnJiZzLmlzQXJyYXkocik/ci5sZW5ndGg6ZyxFPyhzLmhhc093blByb3AocixnKT9yW2ddPVtyW2ddLEldOnJbZ109SSwhbik6KCghcltnXXx8IXMuaXNPYmplY3QocltnXSkpJiYocltnXT1bXSksZSh0LEkscltnXSxpKSYmcy5pc0FycmF5KHJbZ10pJiYocltnXT1zSShyW2ddKSksIW4pfWlmKHMuaXNGb3JtRGF0YShBKSYmcy5pc0Z1bmN0aW9uKEEuZW50cmllcykpe2xldCB0PXt9O3JldHVybiBzLmZvckVhY2hFbnRyeShBLChJLHIpPT57ZShhSShJKSxyLHQsMCl9KSx0fXJldHVybiBudWxsfXZhciBEQT1DSTt2YXIgQkk9eyJDb250ZW50LVR5cGUiOnZvaWQgMH07ZnVuY3Rpb24gUUkoQSxlLHQpe2lmKHMuaXNTdHJpbmcoQSkpdHJ5e3JldHVybihlfHxKU09OLnBhcnNlKShBKSxzLnRyaW0oQSl9Y2F0Y2goSSl7aWYoSS5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyBJfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoQSl9dmFyIHlBPXt0cmFuc2l0aW9uYWw6bUEsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihlLHQpe2xldCBJPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIscj1JLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxpPXMuaXNPYmplY3QoZSk7aWYoaSYmcy5pc0hUTUxGb3JtKGUpJiYoZT1uZXcgRm9ybURhdGEoZSkpLHMuaXNGb3JtRGF0YShlKSlyZXR1cm4gciYmcj9KU09OLnN0cmluZ2lmeShEQShlKSk6ZTtpZihzLmlzQXJyYXlCdWZmZXIoZSl8fHMuaXNCdWZmZXIoZSl8fHMuaXNTdHJlYW0oZSl8fHMuaXNGaWxlKGUpfHxzLmlzQmxvYihlKSlyZXR1cm4gZTtpZihzLmlzQXJyYXlCdWZmZXJWaWV3KGUpKXJldHVybiBlLmJ1ZmZlcjtpZihzLmlzVVJMU2VhcmNoUGFyYW1zKGUpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLGUudG9TdHJpbmcoKTtsZXQgbjtpZihpKXtpZihJLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiBXQShlLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKG49cy5pc0ZpbGVMaXN0KGUpKXx8SS5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBFPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gSihuP3siZmlsZXNbXSI6ZX06ZSxFJiZuZXcgRSx0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIGl8fHI/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSxRSShlKSk6ZX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihlKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8eUEudHJhbnNpdGlvbmFsLEk9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxyPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKGUmJnMuaXNTdHJpbmcoZSkmJihJJiYhdGhpcy5yZXNwb25zZVR5cGV8fHIpKXtsZXQgZz0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZyO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShlKX1jYXRjaChuKXtpZihnKXRocm93IG4ubmFtZT09PSJTeW50YXhFcnJvciI/bC5mcm9tKG4sbC5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpufX1yZXR1cm4gZX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6RC5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6RC5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKGUpe3JldHVybiBlPj0yMDAmJmU8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIn19fTtzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIl0sZnVuY3Rpb24oZSl7eUEuaGVhZGVyc1tlXT17fX0pO3MuZm9yRWFjaChbInBvc3QiLCJwdXQiLCJwYXRjaCJdLGZ1bmN0aW9uKGUpe3lBLmhlYWRlcnNbZV09cy5tZXJnZShCSSl9KTt2YXIgaj15QTt2YXIgRUk9cy50b09iamVjdFNldChbImFnZSIsImF1dGhvcml6YXRpb24iLCJjb250ZW50LWxlbmd0aCIsImNvbnRlbnQtdHlwZSIsImV0YWciLCJleHBpcmVzIiwiZnJvbSIsImhvc3QiLCJpZi1tb2RpZmllZC1zaW5jZSIsImlmLXVubW9kaWZpZWQtc2luY2UiLCJsYXN0LW1vZGlmaWVkIiwibG9jYXRpb24iLCJtYXgtZm9yd2FyZHMiLCJwcm94eS1hdXRob3JpemF0aW9uIiwicmVmZXJlciIsInJldHJ5LWFmdGVyIiwidXNlci1hZ2VudCJdKSxUZT1BPT57bGV0IGU9e30sdCxJLHI7cmV0dXJuIEEmJkEuc3BsaXQoYCUwQWApLmZvckVhY2goZnVuY3Rpb24oZyl7cj1nLmluZGV4T2YoIjoiKSx0PWcuc3Vic3RyaW5nKDAscikudHJpbSgpLnRvTG93ZXJDYXNlKCksST1nLnN1YnN0cmluZyhyKzEpLnRyaW0oKSwhKCF0fHxlW3RdJiZFSVt0XSkmJih0PT09InNldC1jb29raWUiP2VbdF0/ZVt0XS5wdXNoKEkpOmVbdF09W0ldOmVbdF09ZVt0XT9lW3RdKyIsICIrSTpJKX0pLGV9O3ZhciBLZT1TeW1ib2woImludGVybmFscyIpO2Z1bmN0aW9uIGVBKEEpe3JldHVybiBBJiZTdHJpbmcoQSkudHJpbSgpLnRvTG93ZXJDYXNlKCl9ZnVuY3Rpb24gd0EoQSl7cmV0dXJuIEE9PT0hMXx8QT09bnVsbD9BOnMuaXNBcnJheShBKT9BLm1hcCh3QSk6U3RyaW5nKEEpfWZ1bmN0aW9uIGNJKEEpe2xldCBlPU9iamVjdC5jcmVhdGUobnVsbCksdD0vKFteXFxzLDs9XSspXFxzKig/Oj1cXHMqKFteLDtdKykpPy9nLEk7Zm9yKDtJPXQuZXhlYyhBKTspZVtJWzFdXT1JWzJdO3JldHVybiBlfXZhciBmST1BPT4vXlstX2EtekEtWjAtOV5gfH4sISUyMyQlJlwnKisuXSskLy50ZXN0KEEudHJpbSgpKTtmdW5jdGlvbiBqQShBLGUsdCxJLHIpe2lmKHMuaXNGdW5jdGlvbihJKSlyZXR1cm4gSS5jYWxsKHRoaXMsZSx0KTtpZihyJiYoZT10KSwhIXMuaXNTdHJpbmcoZSkpe2lmKHMuaXNTdHJpbmcoSSkpcmV0dXJuIGUuaW5kZXhPZihJKSE9PS0xO2lmKHMuaXNSZWdFeHAoSSkpcmV0dXJuIEkudGVzdChlKX19ZnVuY3Rpb24gbEkoQSl7cmV0dXJuIEEudHJpbSgpLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvKFthLXpcXGRdKShcXHcqKS9nLChlLHQsSSk9PnQudG9VcHBlckNhc2UoKStJKX1mdW5jdGlvbiB1SShBLGUpe2xldCB0PXMudG9DYW1lbENhc2UoIiAiK2UpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChJPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsSSt0LHt2YWx1ZTpmdW5jdGlvbihyLGksZyl7cmV0dXJuIHRoaXNbSV0uY2FsbCh0aGlzLGUscixpLGcpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBaPWNsYXNze2NvbnN0cnVjdG9yKGUpe2UmJnRoaXMuc2V0KGUpfXNldChlLHQsSSl7bGV0IHI9dGhpcztmdW5jdGlvbiBpKG4sRSxvKXtsZXQgQj1lQShFKTtpZighQil0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IGM9cy5maW5kS2V5KHIsQik7KCFjfHxyW2NdPT09dm9pZCAwfHxvPT09ITB8fG89PT12b2lkIDAmJnJbY10hPT0hMSkmJihyW2N8fEVdPXdBKG4pKX1sZXQgZz0obixFKT0+cy5mb3JFYWNoKG4sKG8sQik9PmkobyxCLEUpKTtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KGUpfHxlIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9nKGUsdCk6cy5pc1N0cmluZyhlKSYmKGU9ZS50cmltKCkpJiYhZkkoZSk/ZyhUZShlKSx0KTplIT1udWxsJiZpKHQsZSxJKSx0aGlzfWdldChlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IEk9cy5maW5kS2V5KHRoaXMsZSk7aWYoSSl7bGV0IHI9dGhpc1tJXTtpZighdClyZXR1cm4gcjtpZih0PT09ITApcmV0dXJuIGNJKHIpO2lmKHMuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMscixJKTtpZihzLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMocik7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhlLHQpe2lmKGU9ZUEoZSksZSl7bGV0IEk9cy5maW5kS2V5KHRoaXMsZSk7cmV0dXJuISEoSSYmdGhpc1tJXSE9PXZvaWQgMCYmKCF0fHxqQSh0aGlzLHRoaXNbSV0sSSx0KSkpfXJldHVybiExfWRlbGV0ZShlLHQpe2xldCBJPXRoaXMscj0hMTtmdW5jdGlvbiBpKGcpe2lmKGc9ZUEoZyksZyl7bGV0IG49cy5maW5kS2V5KEksZyk7biYmKCF0fHxqQShJLElbbl0sbix0KSkmJihkZWxldGUgSVtuXSxyPSEwKX19cmV0dXJuIHMuaXNBcnJheShlKT9lLmZvckVhY2goaSk6aShlKSxyfWNsZWFyKGUpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLEk9dC5sZW5ndGgscj0hMTtmb3IoO0ktLTspe2xldCBpPXRbSV07KCFlfHxqQSh0aGlzLHRoaXNbaV0saSxlLCEwKSkmJihkZWxldGUgdGhpc1tpXSxyPSEwKX1yZXR1cm4gcn1ub3JtYWxpemUoZSl7bGV0IHQ9dGhpcyxJPXt9O3JldHVybiBzLmZvckVhY2godGhpcywocixpKT0+e2xldCBnPXMuZmluZEtleShJLGkpO2lmKGcpe3RbZ109d0EociksZGVsZXRlIHRbaV07cmV0dXJufWxldCBuPWU/bEkoaSk6U3RyaW5nKGkpLnRyaW0oKTtuIT09aSYmZGVsZXRlIHRbaV0sdFtuXT13QShyKSxJW25dPSEwfSksdGhpc31jb25jYXQoLi4uZSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uZSl9dG9KU09OKGUpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChJLHIpPT57SSE9bnVsbCYmSSE9PSExJiYodFtyXT1lJiZzLmlzQXJyYXkoSSk/SS5qb2luKCIsICIpOkkpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbZSx0XSk9PmUrIjogIit0KS5qb2luKGAlMEFgKX1nZXRbU3ltYm9sLnRvU3RyaW5nVGFnXSgpe3JldHVybiJBeGlvc0hlYWRlcnMifXN0YXRpYyBmcm9tKGUpe3JldHVybiBlIGluc3RhbmNlb2YgdGhpcz9lOm5ldyB0aGlzKGUpfXN0YXRpYyBjb25jYXQoZSwuLi50KXtsZXQgST1uZXcgdGhpcyhlKTtyZXR1cm4gdC5mb3JFYWNoKHI9Pkkuc2V0KHIpKSxJfXN0YXRpYyBhY2Nlc3NvcihlKXtsZXQgST0odGhpc1tLZV09dGhpc1tLZV09e2FjY2Vzc29yczp7fX0pLmFjY2Vzc29ycyxyPXRoaXMucHJvdG90eXBlO2Z1bmN0aW9uIGkoZyl7bGV0IG49ZUEoZyk7SVtuXXx8KHVJKHIsZyksSVtuXT0hMCl9cmV0dXJuIHMuaXNBcnJheShlKT9lLmZvckVhY2goaSk6aShlKSx0aGlzfX07Wi5hY2Nlc3NvcihbIkNvbnRlbnQtVHlwZSIsIkNvbnRlbnQtTGVuZ3RoIiwiQWNjZXB0IiwiQWNjZXB0LUVuY29kaW5nIiwiVXNlci1BZ2VudCIsIkF1dGhvcml6YXRpb24iXSk7cy5mcmVlemVNZXRob2RzKFoucHJvdG90eXBlKTtzLmZyZWV6ZU1ldGhvZHMoWik7dmFyIHA9WjtmdW5jdGlvbiB0QShBLGUpe2xldCB0PXRoaXN8fGosST1lfHx0LHI9cC5mcm9tKEkuaGVhZGVycyksaT1JLmRhdGE7cmV0dXJuIHMuZm9yRWFjaChBLGZ1bmN0aW9uKG4pe2k9bi5jYWxsKHQsaSxyLm5vcm1hbGl6ZSgpLGU/ZS5zdGF0dXM6dm9pZCAwKX0pLHIubm9ybWFsaXplKCksaX1mdW5jdGlvbiBJQShBKXtyZXR1cm4hIShBJiZBLl9fQ0FOQ0VMX18pfWZ1bmN0aW9uIHhlKEEsZSx0KXtsLmNhbGwodGhpcyxBPz8iY2FuY2VsZWQiLGwuRVJSX0NBTkNFTEVELGUsdCksdGhpcy5uYW1lPSJDYW5jZWxlZEVycm9yIn1zLmluaGVyaXRzKHhlLGwse19fQ0FOQ0VMX186ITB9KTt2YXIgTT14ZTtmdW5jdGlvbiBaQShBLGUsdCl7bGV0IEk9dC5jb25maWcudmFsaWRhdGVTdGF0dXM7IXQuc3RhdHVzfHwhSXx8SSh0LnN0YXR1cyk/QSh0KTplKG5ldyBsKCJSZXF1ZXN0IGZhaWxlZCB3aXRoIHN0YXR1cyBjb2RlICIrdC5zdGF0dXMsW2wuRVJSX0JBRF9SRVFVRVNULGwuRVJSX0JBRF9SRVNQT05TRV1bTWF0aC5mbG9vcih0LnN0YXR1cy8xMDApLTRdLHQuY29uZmlnLHQucmVxdWVzdCx0KSl9dmFyIFBlPUQuaXNTdGFuZGFyZEJyb3dzZXJFbnY/ZnVuY3Rpb24oKXtyZXR1cm57d3JpdGU6ZnVuY3Rpb24odCxJLHIsaSxnLG4pe2xldCBFPVtdO0UucHVzaCh0KyI9IitlbmNvZGVVUklDb21wb25lbnQoSSkpLHMuaXNOdW1iZXIocikmJkUucHVzaCgiZXhwaXJlcz0iK25ldyBEYXRlKHIpLnRvR01UU3RyaW5nKCkpLHMuaXNTdHJpbmcoaSkmJkUucHVzaCgicGF0aD0iK2kpLHMuaXNTdHJpbmcoZykmJkUucHVzaCgiZG9tYWluPSIrZyksbj09PSEwJiZFLnB1c2goInNlY3VyZSIpLGRvY3VtZW50LmNvb2tpZT1FLmpvaW4oIjsgIil9LHJlYWQ6ZnVuY3Rpb24odCl7bGV0IEk9ZG9jdW1lbnQuY29va2llLm1hdGNoKG5ldyBSZWdFeHAoIihefDtcXFxccyopKCIrdCsiKT0oW147XSopIikpO3JldHVybiBJP2RlY29kZVVSSUNvbXBvbmVudChJWzNdKTpudWxsfSxyZW1vdmU6ZnVuY3Rpb24odCl7dGhpcy53cml0ZSh0LCIiLERhdGUubm93KCktODY0ZTUpfX19KCk6ZnVuY3Rpb24oKXtyZXR1cm57d3JpdGU6ZnVuY3Rpb24oKXt9LHJlYWQ6ZnVuY3Rpb24oKXtyZXR1cm4gbnVsbH0scmVtb3ZlOmZ1bmN0aW9uKCl7fX19KCk7ZnVuY3Rpb24gX0EoQSl7cmV0dXJuL14oW2Etel1bYS16XFxkK1xcLS5dKjopP1xcL1xcLy9pLnRlc3QoQSl9ZnVuY3Rpb24gVkEoQSxlKXtyZXR1cm4gZT9BLnJlcGxhY2UoL1xcLyskLywiIikrIi8iK2UucmVwbGFjZSgvXlxcLysvLCIiKTpBfWZ1bmN0aW9uIHJBKEEsZSl7cmV0dXJuIEEmJiFfQShlKT9WQShBLGUpOmV9dmFyIFdlPUQuaXNTdGFuZGFyZEJyb3dzZXJFbnY/ZnVuY3Rpb24oKXtsZXQgZT0vKG1zaWV8dHJpZGVudCkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpLHQ9ZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgiYSIpLEk7ZnVuY3Rpb24gcihpKXtsZXQgZz1pO3JldHVybiBlJiYodC5zZXRBdHRyaWJ1dGUoImhyZWYiLGcpLGc9dC5ocmVmKSx0LnNldEF0dHJpYnV0ZSgiaHJlZiIsZykse2hyZWY6dC5ocmVmLHByb3RvY29sOnQucHJvdG9jb2w/dC5wcm90b2NvbC5yZXBsYWNlKC86JC8sIiIpOiIiLGhvc3Q6dC5ob3N0LHNlYXJjaDp0LnNlYXJjaD90LnNlYXJjaC5yZXBsYWNlKC9eXFw/LywiIik6IiIsaGFzaDp0Lmhhc2g/dC5oYXNoLnJlcGxhY2UoL14lMjMvLCIiKToiIixob3N0bmFtZTp0Lmhvc3RuYW1lLHBvcnQ6dC5wb3J0LHBhdGhuYW1lOnQucGF0aG5hbWUuY2hhckF0KDApPT09Ii8iP3QucGF0aG5hbWU6Ii8iK3QucGF0aG5hbWV9fXJldHVybiBJPXIod2luZG93LmxvY2F0aW9uLmhyZWYpLGZ1bmN0aW9uKGcpe2xldCBuPXMuaXNTdHJpbmcoZyk/cihnKTpnO3JldHVybiBuLnByb3RvY29sPT09SS5wcm90b2NvbCYmbi5ob3N0PT09SS5ob3N0fX0oKTpmdW5jdGlvbigpe3JldHVybiBmdW5jdGlvbigpe3JldHVybiEwfX0oKTtmdW5jdGlvbiB6QShBKXtsZXQgZT0vXihbLStcXHddezEsMjV9KSg6P1xcL1xcL3w6KS8uZXhlYyhBKTtyZXR1cm4gZSYmZVsxXXx8IiJ9ZnVuY3Rpb24gaEkoQSxlKXtBPUF8fDEwO2xldCB0PW5ldyBBcnJheShBKSxJPW5ldyBBcnJheShBKSxyPTAsaT0wLGc7cmV0dXJuIGU9ZSE9PXZvaWQgMD9lOjFlMyxmdW5jdGlvbihFKXtsZXQgbz1EYXRlLm5vdygpLEI9SVtpXTtnfHwoZz1vKSx0W3JdPUUsSVtyXT1vO2xldCBjPWksYT0wO2Zvcig7YyE9PXI7KWErPXRbYysrXSxjPWMlQTtpZihyPShyKzEpJUEscj09PWkmJihpPShpKzEpJUEpLG8tZzxlKXJldHVybjtsZXQgQz1CJiZvLUI7cmV0dXJuIEM/TWF0aC5yb3VuZChhKjFlMy9DKTp2b2lkIDB9fXZhciBqZT1oSTtmdW5jdGlvbiBaZShBLGUpe2xldCB0PTAsST1qZSg1MCwyNTApO3JldHVybiByPT57bGV0IGk9ci5sb2FkZWQsZz1yLmxlbmd0aENvbXB1dGFibGU/ci50b3RhbDp2b2lkIDAsbj1pLXQsRT1JKG4pLG89aTw9Zzt0PWk7bGV0IEI9e2xvYWRlZDppLHRvdGFsOmcscHJvZ3Jlc3M6Zz9pL2c6dm9pZCAwLGJ5dGVzOm4scmF0ZTpFfHx2b2lkIDAsZXN0aW1hdGVkOkUmJmcmJm8/KGctaSkvRTp2b2lkIDAsZXZlbnQ6cn07QltlPyJkb3dubG9hZCI6InVwbG9hZCJdPSEwLEEoQil9fXZhciBkST10eXBlb2YgWE1MSHR0cFJlcXVlc3Q8InUiLF9lPWRJJiZmdW5jdGlvbihBKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24odCxJKXtsZXQgcj1BLmRhdGEsaT1wLmZyb20oQS5oZWFkZXJzKS5ub3JtYWxpemUoKSxnPUEucmVzcG9uc2VUeXBlLG47ZnVuY3Rpb24gRSgpe0EuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udW5zdWJzY3JpYmUobiksQS5zaWduYWwmJkEuc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoImFib3J0IixuKX1zLmlzRm9ybURhdGEocikmJihELmlzU3RhbmRhcmRCcm93c2VyRW52fHxELmlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52P2kuc2V0Q29udGVudFR5cGUoITEpOmkuc2V0Q29udGVudFR5cGUoIm11bHRpcGFydC9mb3JtLWRhdGE7IiwhMSkpO2xldCBvPW5ldyBYTUxIdHRwUmVxdWVzdDtpZihBLmF1dGgpe2xldCBDPUEuYXV0aC51c2VybmFtZXx8IiIsUT1BLmF1dGgucGFzc3dvcmQ/dW5lc2NhcGUoZW5jb2RlVVJJQ29tcG9uZW50KEEuYXV0aC5wYXNzd29yZCkpOiIiO2kuc2V0KCJBdXRob3JpemF0aW9uIiwiQmFzaWMgIitidG9hKEMrIjoiK1EpKX1sZXQgQj1yQShBLmJhc2VVUkwsQS51cmwpO28ub3BlbihBLm1ldGhvZC50b1VwcGVyQ2FzZSgpLEFBKEIsQS5wYXJhbXMsQS5wYXJhbXNTZXJpYWxpemVyKSwhMCksby50aW1lb3V0PUEudGltZW91dDtmdW5jdGlvbiBjKCl7aWYoIW8pcmV0dXJuO2xldCBDPXAuZnJvbSgiZ2V0QWxsUmVzcG9uc2VIZWFkZXJzImluIG8mJm8uZ2V0QWxsUmVzcG9uc2VIZWFkZXJzKCkpLGY9e2RhdGE6IWd8fGc9PT0idGV4dCJ8fGc9PT0ianNvbiI/by5yZXNwb25zZVRleHQ6by5yZXNwb25zZSxzdGF0dXM6by5zdGF0dXMsc3RhdHVzVGV4dDpvLnN0YXR1c1RleHQsaGVhZGVyczpDLGNvbmZpZzpBLHJlcXVlc3Q6b307WkEoZnVuY3Rpb24odyl7dCh3KSxFKCl9LGZ1bmN0aW9uKHcpe0kodyksRSgpfSxmKSxvPW51bGx9aWYoIm9ubG9hZGVuZCJpbiBvP28ub25sb2FkZW5kPWM6by5vbnJlYWR5c3RhdGVjaGFuZ2U9ZnVuY3Rpb24oKXshb3x8by5yZWFkeVN0YXRlIT09NHx8by5zdGF0dXM9PT0wJiYhKG8ucmVzcG9uc2VVUkwmJm8ucmVzcG9uc2VVUkwuaW5kZXhPZigiZmlsZToiKT09PTApfHxzZXRUaW1lb3V0KGMpfSxvLm9uYWJvcnQ9ZnVuY3Rpb24oKXtvJiYoSShuZXcgbCgiUmVxdWVzdCBhYm9ydGVkIixsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGwpfSxvLm9uZXJyb3I9ZnVuY3Rpb24oKXtJKG5ldyBsKCJOZXR3b3JrIEVycm9yIixsLkVSUl9ORVRXT1JLLEEsbykpLG89bnVsbH0sby5vbnRpbWVvdXQ9ZnVuY3Rpb24oKXtsZXQgUT1BLnRpbWVvdXQ/InRpbWVvdXQgb2YgIitBLnRpbWVvdXQrIm1zIGV4Y2VlZGVkIjoidGltZW91dCBleGNlZWRlZCIsZj1BLnRyYW5zaXRpb25hbHx8bUE7QS50aW1lb3V0RXJyb3JNZXNzYWdlJiYoUT1BLnRpbWVvdXRFcnJvck1lc3NhZ2UpLEkobmV3IGwoUSxmLmNsYXJpZnlUaW1lb3V0RXJyb3I/bC5FVElNRURPVVQ6bC5FQ09OTkFCT1JURUQsQSxvKSksbz1udWxsfSxELmlzU3RhbmRhcmRCcm93c2VyRW52KXtsZXQgQz0oQS53aXRoQ3JlZGVudGlhbHN8fFdlKEIpKSYmQS54c3JmQ29va2llTmFtZSYmUGUucmVhZChBLnhzcmZDb29raWVOYW1lKTtDJiZpLnNldChBLnhzcmZIZWFkZXJOYW1lLEMpfXI9PT12b2lkIDAmJmkuc2V0Q29udGVudFR5cGUobnVsbCksInNldFJlcXVlc3RIZWFkZXIiaW4gbyYmcy5mb3JFYWNoKGkudG9KU09OKCksZnVuY3Rpb24oUSxmKXtvLnNldFJlcXVlc3RIZWFkZXIoZixRKX0pLHMuaXNVbmRlZmluZWQoQS53aXRoQ3JlZGVudGlhbHMpfHwoby53aXRoQ3JlZGVudGlhbHM9ISFBLndpdGhDcmVkZW50aWFscyksZyYmZyE9PSJqc29uIiYmKG8ucmVzcG9uc2VUeXBlPUEucmVzcG9uc2VUeXBlKSx0eXBlb2YgQS5vbkRvd25sb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm8uYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25Eb3dubG9hZFByb2dyZXNzLCEwKSksdHlwZW9mIEEub25VcGxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby51cGxvYWQmJm8udXBsb2FkLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIixaZShBLm9uVXBsb2FkUHJvZ3Jlc3MpKSwoQS5jYW5jZWxUb2tlbnx8QS5zaWduYWwpJiYobj1DPT57byYmKEkoIUN8fEMudHlwZT9uZXcgTShudWxsLEEsbyk6Qyksby5hYm9ydCgpLG89bnVsbCl9LEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4uc3Vic2NyaWJlKG4pLEEuc2lnbmFsJiYoQS5zaWduYWwuYWJvcnRlZD9uKCk6QS5zaWduYWwuYWRkRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG4pKSk7bGV0IGE9ekEoQik7aWYoYSYmRC5wcm90b2NvbHMuaW5kZXhPZihhKT09PS0xKXtJKG5ldyBsKCJVbnN1cHBvcnRlZCBwcm90b2NvbCAiK2ErIjoiLGwuRVJSX0JBRF9SRVFVRVNULEEpKTtyZXR1cm59by5zZW5kKHJ8fG51bGwpfSl9O3ZhciBwQT17aHR0cDpoQSx4aHI6X2V9O3MuZm9yRWFjaChwQSwoQSxlKT0+e2lmKEEpe3RyeXtPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwibmFtZSIse3ZhbHVlOmV9KX1jYXRjaHt9T2JqZWN0LmRlZmluZVByb3BlcnR5KEEsImFkYXB0ZXJOYW1lIix7dmFsdWU6ZX0pfX0pO3ZhciBWZT17Z2V0QWRhcHRlcjpBPT57QT1zLmlzQXJyYXkoQSk/QTpbQV07bGV0e2xlbmd0aDplfT1BLHQsSTtmb3IobGV0IHI9MDtyPGUmJih0PUFbcl0sIShJPXMuaXNTdHJpbmcodCk/cEFbdC50b0xvd2VyQ2FzZSgpXTp0KSk7cisrKTtpZighSSl0aHJvdyBJPT09ITE/bmV3IGwoYEFkYXB0ZXIgJHt0fSBpcyBub3Qgc3VwcG9ydGVkIGJ5IHRoZSBlbnZpcm9ubWVudGAsIkVSUl9OT1RfU1VQUE9SVCIpOm5ldyBFcnJvcihzLmhhc093blByb3AocEEsdCk/YEFkYXB0ZXIgXCcke3R9XCcgaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgYnVpbGRgOmBVbmtub3duIGFkYXB0ZXIgXCcke3R9XCdgKTtpZighcy5pc0Z1bmN0aW9uKEkpKXRocm93IG5ldyBUeXBlRXJyb3IoImFkYXB0ZXIgaXMgbm90IGEgZnVuY3Rpb24iKTtyZXR1cm4gSX0sYWRhcHRlcnM6cEF9O2Z1bmN0aW9uIFhBKEEpe2lmKEEuY2FuY2VsVG9rZW4mJkEuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLEEuc2lnbmFsJiZBLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyBNKG51bGwsQSl9ZnVuY3Rpb24gRkEoQSl7cmV0dXJuIFhBKEEpLEEuaGVhZGVycz1wLmZyb20oQS5oZWFkZXJzKSxBLmRhdGE9dEEuY2FsbChBLEEudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKEEubWV0aG9kKSE9PS0xJiZBLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLFZlLmdldEFkYXB0ZXIoQS5hZGFwdGVyfHxqLmFkYXB0ZXIpKEEpLnRoZW4oZnVuY3Rpb24oSSl7cmV0dXJuIFhBKEEpLEkuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxJKSxJLmhlYWRlcnM9cC5mcm9tKEkuaGVhZGVycyksSX0sZnVuY3Rpb24oSSl7cmV0dXJuIElBKEkpfHwoWEEoQSksSSYmSS5yZXNwb25zZSYmKEkucmVzcG9uc2UuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXNwb25zZSxJLnJlc3BvbnNlKSxJLnJlc3BvbnNlLmhlYWRlcnM9cC5mcm9tKEkucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChJKX0pfXZhciB6ZT1BPT5BIGluc3RhbmNlb2YgcD9BLnRvSlNPTigpOkE7ZnVuY3Rpb24gayhBLGUpe2U9ZXx8e307bGV0IHQ9e307ZnVuY3Rpb24gSShvLEIsYyl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChvKSYmcy5pc1BsYWluT2JqZWN0KEIpP3MubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6Y30sbyxCKTpzLmlzUGxhaW5PYmplY3QoQik/cy5tZXJnZSh7fSxCKTpzLmlzQXJyYXkoQik/Qi5zbGljZSgpOkJ9ZnVuY3Rpb24gcihvLEIsYyl7aWYocy5pc1VuZGVmaW5lZChCKSl7aWYoIXMuaXNVbmRlZmluZWQobykpcmV0dXJuIEkodm9pZCAwLG8sYyl9ZWxzZSByZXR1cm4gSShvLEIsYyl9ZnVuY3Rpb24gaShvLEIpe2lmKCFzLmlzVW5kZWZpbmVkKEIpKXJldHVybiBJKHZvaWQgMCxCKX1mdW5jdGlvbiBnKG8sQil7aWYocy5pc1VuZGVmaW5lZChCKSl7aWYoIXMuaXNVbmRlZmluZWQobykpcmV0dXJuIEkodm9pZCAwLG8pfWVsc2UgcmV0dXJuIEkodm9pZCAwLEIpfWZ1bmN0aW9uIG4obyxCLGMpe2lmKGMgaW4gZSlyZXR1cm4gSShvLEIpO2lmKGMgaW4gQSlyZXR1cm4gSSh2b2lkIDAsbyl9bGV0IEU9e3VybDppLG1ldGhvZDppLGRhdGE6aSxiYXNlVVJMOmcsdHJhbnNmb3JtUmVxdWVzdDpnLHRyYW5zZm9ybVJlc3BvbnNlOmcscGFyYW1zU2VyaWFsaXplcjpnLHRpbWVvdXQ6Zyx0aW1lb3V0TWVzc2FnZTpnLHdpdGhDcmVkZW50aWFsczpnLGFkYXB0ZXI6ZyxyZXNwb25zZVR5cGU6Zyx4c3JmQ29va2llTmFtZTpnLHhzcmZIZWFkZXJOYW1lOmcsb25VcGxvYWRQcm9ncmVzczpnLG9uRG93bmxvYWRQcm9ncmVzczpnLGRlY29tcHJlc3M6ZyxtYXhDb250ZW50TGVuZ3RoOmcsbWF4Qm9keUxlbmd0aDpnLGJlZm9yZVJlZGlyZWN0OmcsdHJhbnNwb3J0OmcsaHR0cEFnZW50OmcsaHR0cHNBZ2VudDpnLGNhbmNlbFRva2VuOmcsc29ja2V0UGF0aDpnLHJlc3BvbnNlRW5jb2Rpbmc6Zyx2YWxpZGF0ZVN0YXR1czpuLGhlYWRlcnM6KG8sQik9PnIoemUobyksemUoQiksITApfTtyZXR1cm4gcy5mb3JFYWNoKE9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30sQSxlKSksZnVuY3Rpb24oQil7bGV0IGM9RVtCXXx8cixhPWMoQVtCXSxlW0JdLEIpO3MuaXNVbmRlZmluZWQoYSkmJmMhPT1ufHwodFtCXT1hKX0pLHR9dmFyIFNBPSIxLjQuMCI7dmFyIHZBPXt9O1sib2JqZWN0IiwiYm9vbGVhbiIsIm51bWJlciIsImZ1bmN0aW9uIiwic3RyaW5nIiwic3ltYm9sIl0uZm9yRWFjaCgoQSxlKT0+e3ZBW0FdPWZ1bmN0aW9uKEkpe3JldHVybiB0eXBlb2YgST09PUF8fCJhIisoZTwxPyJuICI6IiAiKStBfX0pO3ZhciBYZT17fTt2QS50cmFuc2l0aW9uYWw9ZnVuY3Rpb24oZSx0LEkpe2Z1bmN0aW9uIHIoaSxnKXtyZXR1cm4iW0F4aW9zIHYiK1NBKyJdIFRyYW5zaXRpb25hbCBvcHRpb24gXCciK2krIlwnIitnKyhJPyIuICIrSToiIil9cmV0dXJuKGksZyxuKT0+e2lmKGU9PT0hMSl0aHJvdyBuZXcgbChyKGcsIiBoYXMgYmVlbiByZW1vdmVkIisodD8iIGluICIrdDoiIikpLGwuRVJSX0RFUFJFQ0FURUQpO3JldHVybiB0JiYhWGVbZ10mJihYZVtnXT0hMCxjb25zb2xlLndhcm4ocihnLCIgaGFzIGJlZW4gZGVwcmVjYXRlZCBzaW5jZSB2Iit0KyIgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiB0aGUgbmVhciBmdXR1cmUiKSkpLGU/ZShpLGcsbik6ITB9fTtmdW5jdGlvbiBtSShBLGUsdCl7aWYodHlwZW9mIEEhPSJvYmplY3QiKXRocm93IG5ldyBsKCJvcHRpb25zIG11c3QgYmUgYW4gb2JqZWN0IixsLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtsZXQgST1PYmplY3Qua2V5cyhBKSxyPUkubGVuZ3RoO2Zvcig7ci0tID4wOyl7bGV0IGk9SVtyXSxnPWVbaV07aWYoZyl7bGV0IG49QVtpXSxFPW49PT12b2lkIDB8fGcobixpLEEpO2lmKEUhPT0hMCl0aHJvdyBuZXcgbCgib3B0aW9uICIraSsiIG11c3QgYmUgIitFLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2NvbnRpbnVlfWlmKHQhPT0hMCl0aHJvdyBuZXcgbCgiVW5rbm93biBvcHRpb24gIitpLGwuRVJSX0JBRF9PUFRJT04pfX12YXIgTkE9e2Fzc2VydE9wdGlvbnM6bUksdmFsaWRhdG9yczp2QX07dmFyIGI9TkEudmFsaWRhdG9ycyxfPWNsYXNze2NvbnN0cnVjdG9yKGUpe3RoaXMuZGVmYXVsdHM9ZSx0aGlzLmludGVyY2VwdG9ycz17cmVxdWVzdDpuZXcgUEEscmVzcG9uc2U6bmV3IFBBfX1yZXF1ZXN0KGUsdCl7dHlwZW9mIGU9PSJzdHJpbmciPyh0PXR8fHt9LHQudXJsPWUpOnQ9ZXx8e30sdD1rKHRoaXMuZGVmYXVsdHMsdCk7bGV0e3RyYW5zaXRpb25hbDpJLHBhcmFtc1NlcmlhbGl6ZXI6cixoZWFkZXJzOml9PXQ7SSE9PXZvaWQgMCYmTkEuYXNzZXJ0T3B0aW9ucyhJLHtzaWxlbnRKU09OUGFyc2luZzpiLnRyYW5zaXRpb25hbChiLmJvb2xlYW4pLGZvcmNlZEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksY2xhcmlmeVRpbWVvdXRFcnJvcjpiLnRyYW5zaXRpb25hbChiLmJvb2xlYW4pfSwhMSksciE9bnVsbCYmKHMuaXNGdW5jdGlvbihyKT90LnBhcmFtc1NlcmlhbGl6ZXI9e3NlcmlhbGl6ZTpyfTpOQS5hc3NlcnRPcHRpb25zKHIse2VuY29kZTpiLmZ1bmN0aW9uLHNlcmlhbGl6ZTpiLmZ1bmN0aW9ufSwhMCkpLHQubWV0aG9kPSh0Lm1ldGhvZHx8dGhpcy5kZWZhdWx0cy5tZXRob2R8fCJnZXQiKS50b0xvd2VyQ2FzZSgpO2xldCBnO2c9aSYmcy5tZXJnZShpLmNvbW1vbixpW3QubWV0aG9kXSksZyYmcy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCIsImNvbW1vbiJdLFE9PntkZWxldGUgaVtRXX0pLHQuaGVhZGVycz1wLmNvbmNhdChnLGkpO2xldCBuPVtdLEU9ITA7dGhpcy5pbnRlcmNlcHRvcnMucmVxdWVzdC5mb3JFYWNoKGZ1bmN0aW9uKGYpe3R5cGVvZiBmLnJ1bldoZW49PSJmdW5jdGlvbiImJmYucnVuV2hlbih0KT09PSExfHwoRT1FJiZmLnN5bmNocm9ub3VzLG4udW5zaGlmdChmLmZ1bGZpbGxlZCxmLnJlamVjdGVkKSl9KTtsZXQgbz1bXTt0aGlzLmludGVyY2VwdG9ycy5yZXNwb25zZS5mb3JFYWNoKGZ1bmN0aW9uKGYpe28ucHVzaChmLmZ1bGZpbGxlZCxmLnJlamVjdGVkKX0pO2xldCBCLGM9MCxhO2lmKCFFKXtsZXQgUT1bRkEuYmluZCh0aGlzKSx2b2lkIDBdO2ZvcihRLnVuc2hpZnQuYXBwbHkoUSxuKSxRLnB1c2guYXBwbHkoUSxvKSxhPVEubGVuZ3RoLEI9UHJvbWlzZS5yZXNvbHZlKHQpO2M8YTspQj1CLnRoZW4oUVtjKytdLFFbYysrXSk7cmV0dXJuIEJ9YT1uLmxlbmd0aDtsZXQgQz10O2ZvcihjPTA7YzxhOyl7bGV0IFE9bltjKytdLGY9bltjKytdO3RyeXtDPVEoQyl9Y2F0Y2gobSl7Zi5jYWxsKHRoaXMsbSk7YnJlYWt9fXRyeXtCPUZBLmNhbGwodGhpcyxDKX1jYXRjaChRKXtyZXR1cm4gUHJvbWlzZS5yZWplY3QoUSl9Zm9yKGM9MCxhPW8ubGVuZ3RoO2M8YTspQj1CLnRoZW4ob1tjKytdLG9bYysrXSk7cmV0dXJuIEJ9Z2V0VXJpKGUpe2U9ayh0aGlzLmRlZmF1bHRzLGUpO2xldCB0PXJBKGUuYmFzZVVSTCxlLnVybCk7cmV0dXJuIEFBKHQsZS5wYXJhbXMsZS5wYXJhbXNTZXJpYWxpemVyKX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiLCJvcHRpb25zIl0sZnVuY3Rpb24oZSl7Xy5wcm90b3R5cGVbZV09ZnVuY3Rpb24odCxJKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KGsoSXx8e30se21ldGhvZDplLHVybDp0LGRhdGE6KEl8fHt9KS5kYXRhfSkpfX0pO3MuZm9yRWFjaChbInBvc3QiLCJwdXQiLCJwYXRjaCJdLGZ1bmN0aW9uKGUpe2Z1bmN0aW9uIHQoSSl7cmV0dXJuIGZ1bmN0aW9uKGksZyxuKXtyZXR1cm4gdGhpcy5yZXF1ZXN0KGsobnx8e30se21ldGhvZDplLGhlYWRlcnM6ST97IkNvbnRlbnQtVHlwZSI6Im11bHRpcGFydC9mb3JtLWRhdGEifTp7fSx1cmw6aSxkYXRhOmd9KSl9fV8ucHJvdG90eXBlW2VdPXQoKSxfLnByb3RvdHlwZVtlKyJGb3JtIl09dCghMCl9KTt2YXIgaUE9Xzt2YXIgJEE9Y2xhc3MgQXtjb25zdHJ1Y3RvcihlKXtpZih0eXBlb2YgZSE9ImZ1bmN0aW9uIil0aHJvdyBuZXcgVHlwZUVycm9yKCJleGVjdXRvciBtdXN0IGJlIGEgZnVuY3Rpb24uIik7bGV0IHQ7dGhpcy5wcm9taXNlPW5ldyBQcm9taXNlKGZ1bmN0aW9uKGkpe3Q9aX0pO2xldCBJPXRoaXM7dGhpcy5wcm9taXNlLnRoZW4ocj0+e2lmKCFJLl9saXN0ZW5lcnMpcmV0dXJuO2xldCBpPUkuX2xpc3RlbmVycy5sZW5ndGg7Zm9yKDtpLS0gPjA7KUkuX2xpc3RlbmVyc1tpXShyKTtJLl9saXN0ZW5lcnM9bnVsbH0pLHRoaXMucHJvbWlzZS50aGVuPXI9PntsZXQgaSxnPW5ldyBQcm9taXNlKG49PntJLnN1YnNjcmliZShuKSxpPW59KS50aGVuKHIpO3JldHVybiBnLmNhbmNlbD1mdW5jdGlvbigpe0kudW5zdWJzY3JpYmUoaSl9LGd9LGUoZnVuY3Rpb24oaSxnLG4pe0kucmVhc29ufHwoSS5yZWFzb249bmV3IE0oaSxnLG4pLHQoSS5yZWFzb24pKX0pfXRocm93SWZSZXF1ZXN0ZWQoKXtpZih0aGlzLnJlYXNvbil0aHJvdyB0aGlzLnJlYXNvbn1zdWJzY3JpYmUoZSl7aWYodGhpcy5yZWFzb24pe2UodGhpcy5yZWFzb24pO3JldHVybn10aGlzLl9saXN0ZW5lcnM/dGhpcy5fbGlzdGVuZXJzLnB1c2goZSk6dGhpcy5fbGlzdGVuZXJzPVtlXX11bnN1YnNjcmliZShlKXtpZighdGhpcy5fbGlzdGVuZXJzKXJldHVybjtsZXQgdD10aGlzLl9saXN0ZW5lcnMuaW5kZXhPZihlKTt0IT09LTEmJnRoaXMuX2xpc3RlbmVycy5zcGxpY2UodCwxKX1zdGF0aWMgc291cmNlKCl7bGV0IGU7cmV0dXJue3Rva2VuOm5ldyBBKGZ1bmN0aW9uKHIpe2U9cn0pLGNhbmNlbDplfX19LHZlPSRBO2Z1bmN0aW9uIEFlKEEpe3JldHVybiBmdW5jdGlvbih0KXtyZXR1cm4gQS5hcHBseShudWxsLHQpfX1mdW5jdGlvbiBlZShBKXtyZXR1cm4gcy5pc09iamVjdChBKSYmQS5pc0F4aW9zRXJyb3I9PT0hMH12YXIgdGU9e0NvbnRpbnVlOjEwMCxTd2l0Y2hpbmdQcm90b2NvbHM6MTAxLFByb2Nlc3Npbmc6MTAyLEVhcmx5SGludHM6MTAzLE9rOjIwMCxDcmVhdGVkOjIwMSxBY2NlcHRlZDoyMDIsTm9uQXV0aG9yaXRhdGl2ZUluZm9ybWF0aW9uOjIwMyxOb0NvbnRlbnQ6MjA0LFJlc2V0Q29udGVudDoyMDUsUGFydGlhbENvbnRlbnQ6MjA2LE11bHRpU3RhdHVzOjIwNyxBbHJlYWR5UmVwb3J0ZWQ6MjA4LEltVXNlZDoyMjYsTXVsdGlwbGVDaG9pY2VzOjMwMCxNb3ZlZFBlcm1hbmVudGx5OjMwMSxGb3VuZDozMDIsU2VlT3RoZXI6MzAzLE5vdE1vZGlmaWVkOjMwNCxVc2VQcm94eTozMDUsVW51c2VkOjMwNixUZW1wb3JhcnlSZWRpcmVjdDozMDcsUGVybWFuZW50UmVkaXJlY3Q6MzA4LEJhZFJlcXVlc3Q6NDAwLFVuYXV0aG9yaXplZDo0MDEsUGF5bWVudFJlcXVpcmVkOjQwMixGb3JiaWRkZW46NDAzLE5vdEZvdW5kOjQwNCxNZXRob2ROb3RBbGxvd2VkOjQwNSxOb3RBY2NlcHRhYmxlOjQwNixQcm94eUF1dGhlbnRpY2F0aW9uUmVxdWlyZWQ6NDA3LFJlcXVlc3RUaW1lb3V0OjQwOCxDb25mbGljdDo0MDksR29uZTo0MTAsTGVuZ3RoUmVxdWlyZWQ6NDExLFByZWNvbmRpdGlvbkZhaWxlZDo0MTIsUGF5bG9hZFRvb0xhcmdlOjQxMyxVcmlUb29Mb25nOjQxNCxVbnN1cHBvcnRlZE1lZGlhVHlwZTo0MTUsUmFuZ2VOb3RTYXRpc2ZpYWJsZTo0MTYsRXhwZWN0YXRpb25GYWlsZWQ6NDE3LEltQVRlYXBvdDo0MTgsTWlzZGlyZWN0ZWRSZXF1ZXN0OjQyMSxVbnByb2Nlc3NhYmxlRW50aXR5OjQyMixMb2NrZWQ6NDIzLEZhaWxlZERlcGVuZGVuY3k6NDI0LFRvb0Vhcmx5OjQyNSxVcGdyYWRlUmVxdWlyZWQ6NDI2LFByZWNvbmRpdGlvblJlcXVpcmVkOjQyOCxUb29NYW55UmVxdWVzdHM6NDI5LFJlcXVlc3RIZWFkZXJGaWVsZHNUb29MYXJnZTo0MzEsVW5hdmFpbGFibGVGb3JMZWdhbFJlYXNvbnM6NDUxLEludGVybmFsU2VydmVyRXJyb3I6NTAwLE5vdEltcGxlbWVudGVkOjUwMSxCYWRHYXRld2F5OjUwMixTZXJ2aWNlVW5hdmFpbGFibGU6NTAzLEdhdGV3YXlUaW1lb3V0OjUwNCxIdHRwVmVyc2lvbk5vdFN1cHBvcnRlZDo1MDUsVmFyaWFudEFsc29OZWdvdGlhdGVzOjUwNixJbnN1ZmZpY2llbnRTdG9yYWdlOjUwNyxMb29wRGV0ZWN0ZWQ6NTA4LE5vdEV4dGVuZGVkOjUxMCxOZXR3b3JrQXV0aGVudGljYXRpb25SZXF1aXJlZDo1MTF9O09iamVjdC5lbnRyaWVzKHRlKS5mb3JFYWNoKChbQSxlXSk9Pnt0ZVtlXT1BfSk7dmFyICRlPXRlO2Z1bmN0aW9uIEF0KEEpe2xldCBlPW5ldyBpQShBKSx0PVgoaUEucHJvdG90eXBlLnJlcXVlc3QsZSk7cmV0dXJuIHMuZXh0ZW5kKHQsaUEucHJvdG90eXBlLGUse2FsbE93bktleXM6ITB9KSxzLmV4dGVuZCh0LGUsbnVsbCx7YWxsT3duS2V5czohMH0pLHQuY3JlYXRlPWZ1bmN0aW9uKHIpe3JldHVybiBBdChrKEEscikpfSx0fXZhciBoPUF0KGopO2guQXhpb3M9aUE7aC5DYW5jZWxlZEVycm9yPU07aC5DYW5jZWxUb2tlbj12ZTtoLmlzQ2FuY2VsPUlBO2guVkVSU0lPTj1TQTtoLnRvRm9ybURhdGE9SjtoLkF4aW9zRXJyb3I9bDtoLkNhbmNlbD1oLkNhbmNlbGVkRXJyb3I7aC5hbGw9ZnVuY3Rpb24oZSl7cmV0dXJuIFByb21pc2UuYWxsKGUpfTtoLnNwcmVhZD1BZTtoLmlzQXhpb3NFcnJvcj1lZTtoLm1lcmdlQ29uZmlnPWs7aC5BeGlvc0hlYWRlcnM9cDtoLmZvcm1Ub0pTT049QT0+REEocy5pc0hUTUxGb3JtKEEpP25ldyBGb3JtRGF0YShBKTpBKTtoLkh0dHBTdGF0dXNDb2RlPSRlO2guZGVmYXVsdD1oO3ZhciBSQT1oO3ZhcntBeGlvczpTZyxBeGlvc0Vycm9yOk5nLENhbmNlbGVkRXJyb3I6UmcsaXNDYW5jZWw6R2csQ2FuY2VsVG9rZW46VWcsVkVSU0lPTjprZyxhbGw6TGcsQ2FuY2VsOk9nLGlzQXhpb3NFcnJvcjpKZyxzcHJlYWQ6TWcsdG9Gb3JtRGF0YTpiZyxBeGlvc0hlYWRlcnM6SGcsSHR0cFN0YXR1c0NvZGU6WWcsZm9ybVRvSlNPTjpxZyxtZXJnZUNvbmZpZzpUZ309UkE7dmFyIGdBLEwscmUsSWU9e2Vudjp7ZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aDpmdW5jdGlvbihBKXtyZT1uZXcgVWludDhBcnJheShMLmV4cG9ydHMubWVtb3J5LmJ1ZmZlcil9fX0sR0E9Y2xhc3N7aW5pdCgpe3JldHVybiBnQXx8KHR5cGVvZiBmZXRjaDwidSI/Z0E9ZmV0Y2goImRhdGE6YXBwbGljYXRpb24vd2FzbTtiYXNlNjQsIitldCkudGhlbihlPT5lLmFycmF5QnVmZmVyKCkpLnRoZW4oZT0+V2ViQXNzZW1ibHkuaW5zdGFudGlhdGUoZSxJZSkpLnRoZW4odGhpcy5faW5pdCk6Z0E9V2ViQXNzZW1ibHkuaW5zdGFudGlhdGUoQnVmZmVyLmZyb20oZXQsImJhc2U2NCIpLEllKS50aGVuKHRoaXMuX2luaXQpLGdBKX1faW5pdChlKXtMPWUuaW5zdGFuY2UsSWUuZW52LmVtc2NyaXB0ZW5fbm90aWZ5X21lbW9yeV9ncm93dGgoMCl9ZGVjb2RlKGUsdD0wKXtpZighTCl0aHJvdyBuZXcgRXJyb3IoIlpTVEREZWNvZGVyOiBBd2FpdCAuaW5pdCgpIGJlZm9yZSBkZWNvZGluZy4iKTtsZXQgST1lLmJ5dGVMZW5ndGgscj1MLmV4cG9ydHMubWFsbG9jKEkpO3JlLnNldChlLHIpLHQ9dHx8TnVtYmVyKEwuZXhwb3J0cy5aU1REX2ZpbmREZWNvbXByZXNzZWRTaXplKHIsSSkpO2xldCBpPUwuZXhwb3J0cy5tYWxsb2ModCksZz1MLmV4cG9ydHMuWlNURF9kZWNvbXByZXNzKGksdCxyLEkpLG49cmUuc2xpY2UoaSxpK2cpO3JldHVybiBMLmV4cG9ydHMuZnJlZShyKSxMLmV4cG9ydHMuZnJlZShpKSxufX0sZXQ9IkFHRnpiUUVBQUFBQmJnNWdBMzkvZndGL1lBRi9BWDlnQW45L0FHQUJmd0JnQlg5L2YzOS9BWDlnQTM5L2Z3QmdCSDkvZjM4QmYyQUFBWDlnQW45L0FYOWdCMzkvZjM5L2YzOEJmMkFDZjM4QmZtQUlmMzkvZjM5L2YzOEJmMkFGZjM5L2YzOEFZQTUvZjM5L2YzOS9mMzkvZjM5L2Z3Ri9BaWNCQTJWdWRoOWxiWE5qY21sd2RHVnVYMjV2ZEdsbWVWOXRaVzF2Y25sZlozSnZkM1JvQUFNREl5SUhBQUFCQVFNSEF3RUFDUVFBQlFFSUNBRUZCZ1FFQkFNR0FBQUtBQVVMREEwR0JBVUJjQUVCQVFVSEFRR0FBb0NBQWdZSUFYOEJRWUNqQkFzSHJnRUxCbTFsYlc5eWVRSUFCbTFoYkd4dll3QUZCR1p5WldVQUJneGFVMVJFWDJselJYSnliM0lBRWhsYVUxUkVYMlpwYm1SRVpXTnZiWEJ5WlhOelpXUlRhWHBsQUJ3UFdsTlVSRjlrWldOdmJYQnlaWE56QUNJWlgxOXBibVJwY21WamRGOW1kVzVqZEdsdmJsOTBZV0pzWlFFQUVGOWZaWEp5Ym05ZmJHOWpZWFJwYjI0QUFRbHpkR0ZqYTFOaGRtVUFCd3h6ZEdGamExSmxjM1J2Y21VQUNBcHpkR0ZqYTBGc2JHOWpBQWtLaS9JQklnVUFRWVFmQ3pNQkFYOGdBZ1JBSUFBaEF3TkFJQU1nQVMwQUFEb0FBQ0FEUVFGcUlRTWdBVUVCYWlFQklBSkJBV3NpQWcwQUN3c2dBQXNwQVFGL0lBSUVRQ0FBSVFNRFFDQURJQUU2QUFBZ0EwRUJhaUVESUFKQkFXc2lBZzBBQ3dzZ0FBdHNBUUovUVlBZktBSUFJZ0VnQUVFSGFrRjRjU0lDYWlFQUFrQWdBa0VBSUFBZ0FVMGJEUUFnQUQ4QVFSQjBTd1JBSUFBL0FFRVFkR3RCLy84RGFrRVFka0FBUVg5R0JIOUJBQVZCQUJBQVFRRUxSUTBCQzBHQUh5QUFOZ0lBSUFFUEMwR0VIMEV3TmdJQVFYOEx1U2NCQzM4akFFRVFheUlLSkFBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUlBQkI5QUZOQkVCQmlCOG9BZ0FpQmtFUUlBQkJDMnBCZUhFZ0FFRUxTUnNpQlVFRGRpSUFkaUlCUVFOeEJFQUNRQ0FCUVg5elFRRnhJQUJxSWdKQkEzUWlBVUd3SDJvaUFDQUJRYmdmYWlnQ0FDSUJLQUlJSWdSR0JFQkJpQjhnQmtGK0lBSjNjVFlDQUF3QkN5QUVJQUEyQWd3Z0FDQUVOZ0lJQ3lBQlFRaHFJUUFnQVNBQ1FRTjBJZ0pCQTNJMkFnUWdBU0FDYWlJQklBRW9BZ1JCQVhJMkFnUU1Ed3NnQlVHUUh5Z0NBQ0lIVFEwQklBRUVRQUpBUVFJZ0FIUWlBa0VBSUFKcmNpQUJJQUIwY1dnaUFVRURkQ0lBUWJBZmFpSUNJQUJCdUI5cUtBSUFJZ0FvQWdnaUJFWUVRRUdJSHlBR1FYNGdBWGR4SWdZMkFnQU1BUXNnQkNBQ05nSU1JQUlnQkRZQ0NBc2dBQ0FGUVFOeU5nSUVJQUFnQldvaUNDQUJRUU4wSWdFZ0JXc2lCRUVCY2pZQ0JDQUFJQUZxSUFRMkFnQWdCd1JBSUFkQmVIRkJzQjlxSVFGQm5COG9BZ0FoQWdKL0lBWkJBU0FIUVFOMmRDSURjVVVFUUVHSUh5QURJQVp5TmdJQUlBRU1BUXNnQVNnQ0NBc2hBeUFCSUFJMkFnZ2dBeUFDTmdJTUlBSWdBVFlDRENBQ0lBTTJBZ2dMSUFCQkNHb2hBRUdjSHlBSU5nSUFRWkFmSUFRMkFnQU1Ed3RCakI4b0FnQWlDMFVOQVNBTGFFRUNkRUc0SVdvb0FnQWlBaWdDQkVGNGNTQUZheUVESUFJaEFRTkFBa0FnQVNnQ0VDSUFSUVJBSUFFb0FoUWlBRVVOQVFzZ0FDZ0NCRUY0Y1NBRmF5SUJJQU1nQVNBRFNTSUJHeUVESUFBZ0FpQUJHeUVDSUFBaEFRd0JDd3NnQWlnQ0dDRUpJQUlnQWlnQ0RDSUVSd1JBUVpnZktBSUFHaUFDS0FJSUlnQWdCRFlDRENBRUlBQTJBZ2dNRGdzZ0FrRVVhaUlCS0FJQUlnQkZCRUFnQWlnQ0VDSUFSUTBESUFKQkVHb2hBUXNEUUNBQklRZ2dBQ0lFUVJScUlnRW9BZ0FpQUEwQUlBUkJFR29oQVNBRUtBSVFJZ0FOQUFzZ0NFRUFOZ0lBREEwTFFYOGhCU0FBUWI5L1N3MEFJQUJCQzJvaUFFRjRjU0VGUVl3ZktBSUFJZ2hGRFFCQkFDQUZheUVEQWtBQ1FBSkFBbjlCQUNBRlFZQUNTUTBBR2tFZklBVkIvLy8vQjBzTkFCb2dCVUVtSUFCQkNIWm5JZ0JyZGtFQmNTQUFRUUYwYTBFK2Fnc2lCMEVDZEVHNElXb29BZ0FpQVVVRVFFRUFJUUFNQVF0QkFDRUFJQVZCR1NBSFFRRjJhMEVBSUFkQkgwY2JkQ0VDQTBBQ1FDQUJLQUlFUVhoeElBVnJJZ1lnQTA4TkFDQUJJUVFnQmlJRERRQkJBQ0VESUFFaEFBd0RDeUFBSUFFb0FoUWlCaUFHSUFFZ0FrRWRka0VFY1dvb0FoQWlBVVliSUFBZ0Joc2hBQ0FDUVFGMElRSWdBUTBBQ3dzZ0FDQUVja1VFUUVFQUlRUkJBaUFIZENJQVFRQWdBR3R5SUFoeElnQkZEUU1nQUdoQkFuUkJ1Q0ZxS0FJQUlRQUxJQUJGRFFFTEEwQWdBQ2dDQkVGNGNTQUZheUlDSUFOSklRRWdBaUFESUFFYklRTWdBQ0FFSUFFYklRUWdBQ2dDRUNJQkJIOGdBUVVnQUNnQ0ZBc2lBQTBBQ3dzZ0JFVU5BQ0FEUVpBZktBSUFJQVZyVHcwQUlBUW9BaGdoQnlBRUlBUW9BZ3dpQWtjRVFFR1lIeWdDQUJvZ0JDZ0NDQ0lBSUFJMkFnd2dBaUFBTmdJSURBd0xJQVJCRkdvaUFTZ0NBQ0lBUlFSQUlBUW9BaEFpQUVVTkF5QUVRUkJxSVFFTEEwQWdBU0VHSUFBaUFrRVVhaUlCS0FJQUlnQU5BQ0FDUVJCcUlRRWdBaWdDRUNJQURRQUxJQVpCQURZQ0FBd0xDeUFGUVpBZktBSUFJZ1JOQkVCQm5COG9BZ0FoQUFKQUlBUWdCV3NpQVVFUVR3UkFJQUFnQldvaUFpQUJRUUZ5TmdJRUlBQWdCR29nQVRZQ0FDQUFJQVZCQTNJMkFnUU1BUXNnQUNBRVFRTnlOZ0lFSUFBZ0JHb2lBU0FCS0FJRVFRRnlOZ0lFUVFBaEFrRUFJUUVMUVpBZklBRTJBZ0JCbkI4Z0FqWUNBQ0FBUVFocUlRQU1EUXNnQlVHVUh5Z0NBQ0lDU1FSQVFaUWZJQUlnQldzaUFUWUNBRUdnSDBHZ0h5Z0NBQ0lBSUFWcUlnSTJBZ0FnQWlBQlFRRnlOZ0lFSUFBZ0JVRURjallDQkNBQVFRaHFJUUFNRFF0QkFDRUFJQVZCTDJvaUF3Si9RZUFpS0FJQUJFQkI2Q0lvQWdBTUFRdEI3Q0pDZnpjQ0FFSGtJa0tBb0lDQWdJQUVOd0lBUWVBaUlBcEJER3BCY0hGQjJLclZxZ1Z6TmdJQVFmUWlRUUEyQWdCQnhDSkJBRFlDQUVHQUlBc2lBV29pQmtFQUlBRnJJZ2h4SWdFZ0JVME5ERUhBSWlnQ0FDSUVCRUJCdUNJb0FnQWlCeUFCYWlJSklBZE5JQVFnQ1VseURRMExBa0JCeENJdEFBQkJCSEZGQkVBQ1FBSkFBa0FDUUVHZ0h5Z0NBQ0lFQkVCQnlDSWhBQU5BSUFRZ0FDZ0NBQ0lIVHdSQUlBY2dBQ2dDQkdvZ0JFc05Bd3NnQUNnQ0NDSUFEUUFMQzBFQUVBUWlBa0YvUmcwRElBRWhCa0hrSWlnQ0FDSUFRUUZySWdRZ0FuRUVRQ0FCSUFKcklBSWdCR3BCQUNBQWEzRnFJUVlMSUFVZ0JrOE5BMEhBSWlnQ0FDSUFCRUJCdUNJb0FnQWlCQ0FHYWlJSUlBUk5JQUFnQ0VseURRUUxJQVlRQkNJQUlBSkhEUUVNQlFzZ0JpQUNheUFJY1NJR0VBUWlBaUFBS0FJQUlBQW9BZ1JxUmcwQklBSWhBQXNnQUVGL1JnMEJJQVZCTUdvZ0JrMEVRQ0FBSVFJTUJBdEI2Q0lvQWdBaUFpQURJQVpyYWtFQUlBSnJjU0lDRUFSQmYwWU5BU0FDSUFacUlRWWdBQ0VDREFNTElBSkJmMGNOQWd0QnhDSkJ4Q0lvQWdCQkJISTJBZ0FMSUFFUUJDSUNRWDlHUVFBUUJDSUFRWDlHY2lBQUlBSk5jZzBGSUFBZ0Ftc2lCaUFGUVNocVRRMEZDMEc0SWtHNElpZ0NBQ0FHYWlJQU5nSUFRYndpS0FJQUlBQkpCRUJCdkNJZ0FEWUNBQXNDUUVHZ0h5Z0NBQ0lEQkVCQnlDSWhBQU5BSUFJZ0FDZ0NBQ0lCSUFBb0FnUWlCR3BHRFFJZ0FDZ0NDQ0lBRFFBTERBUUxRWmdmS0FJQUlnQkJBQ0FBSUFKTkcwVUVRRUdZSHlBQ05nSUFDMEVBSVFCQnpDSWdCallDQUVISUlpQUNOZ0lBUWFnZlFYODJBZ0JCckI5QjRDSW9BZ0EyQWdCQjFDSkJBRFlDQUFOQUlBQkJBM1FpQVVHNEgyb2dBVUd3SDJvaUJEWUNBQ0FCUWJ3ZmFpQUVOZ0lBSUFCQkFXb2lBRUVnUncwQUMwR1VIeUFHUVNocklnQkJlQ0FDYTBFSGNTSUJheUlFTmdJQVFhQWZJQUVnQW1vaUFUWUNBQ0FCSUFSQkFYSTJBZ1FnQUNBQ2FrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBUUxJQUlnQTAwZ0FTQURTM0lOQWlBQUtBSU1RUWh4RFFJZ0FDQUVJQVpxTmdJRVFhQWZJQU5CZUNBRGEwRUhjU0lBYWlJQk5nSUFRWlFmUVpRZktBSUFJQVpxSWdJZ0FHc2lBRFlDQUNBQklBQkJBWEkyQWdRZ0FpQURha0VvTmdJRVFhUWZRZkFpS0FJQU5nSUFEQU1MUVFBaEJBd0tDMEVBSVFJTUNBdEJtQjhvQWdBZ0Frc0VRRUdZSHlBQ05nSUFDeUFDSUFacUlRRkJ5Q0loQUFKQUFrQUNRQU5BSUFFZ0FDZ0NBRWNFUUNBQUtBSUlJZ0FOQVF3Q0N3c2dBQzBBREVFSWNVVU5BUXRCeUNJaEFBTkFJQU1nQUNnQ0FDSUJUd1JBSUFFZ0FDZ0NCR29pQkNBRFN3MERDeUFBS0FJSUlRQU1BQXNBQ3lBQUlBSTJBZ0FnQUNBQUtBSUVJQVpxTmdJRUlBSkJlQ0FDYTBFSGNXb2lCeUFGUVFOeU5nSUVJQUZCZUNBQmEwRUhjV29pQmlBRklBZHFJZ1ZySVFBZ0F5QUdSZ1JBUWFBZklBVTJBZ0JCbEI5QmxCOG9BZ0FnQUdvaUFEWUNBQ0FGSUFCQkFYSTJBZ1FNQ0F0Qm5COG9BZ0FnQmtZRVFFR2NIeUFGTmdJQVFaQWZRWkFmS0FJQUlBQnFJZ0EyQWdBZ0JTQUFRUUZ5TmdJRUlBQWdCV29nQURZQ0FBd0lDeUFHS0FJRUlnTkJBM0ZCQVVjTkJpQURRWGh4SVFrZ0EwSC9BVTBFUUNBR0tBSU1JZ0VnQmlnQ0NDSUNSZ1JBUVlnZlFZZ2ZLQUlBUVg0Z0EwRURkbmR4TmdJQURBY0xJQUlnQVRZQ0RDQUJJQUkyQWdnTUJnc2dCaWdDR0NFSUlBWWdCaWdDRENJQ1J3UkFJQVlvQWdnaUFTQUNOZ0lNSUFJZ0FUWUNDQXdGQ3lBR1FSUnFJZ0VvQWdBaUEwVUVRQ0FHS0FJUUlnTkZEUVFnQmtFUWFpRUJDd05BSUFFaEJDQURJZ0pCRkdvaUFTZ0NBQ0lERFFBZ0FrRVFhaUVCSUFJb0FoQWlBdzBBQ3lBRVFRQTJBZ0FNQkF0QmxCOGdCa0VvYXlJQVFYZ2dBbXRCQjNFaUFXc2lDRFlDQUVHZ0h5QUJJQUpxSWdFMkFnQWdBU0FJUVFGeU5nSUVJQUFnQW1wQktEWUNCRUdrSDBId0lpZ0NBRFlDQUNBRElBUkJKeUFFYTBFSGNXcEJMMnNpQUNBQUlBTkJFR3BKR3lJQlFSczJBZ1FnQVVIUUlpa0NBRGNDRUNBQlFjZ2lLUUlBTndJSVFkQWlJQUZCQ0dvMkFnQkJ6Q0lnQmpZQ0FFSElJaUFDTmdJQVFkUWlRUUEyQWdBZ0FVRVlhaUVBQTBBZ0FFRUhOZ0lFSUFCQkNHb2dBRUVFYWlFQUlBUkpEUUFMSUFFZ0EwWU5BQ0FCSUFFb0FnUkJmbkUyQWdRZ0F5QUJJQU5ySWdKQkFYSTJBZ1FnQVNBQ05nSUFJQUpCL3dGTkJFQWdBa0Y0Y1VHd0gyb2hBQUovUVlnZktBSUFJZ0ZCQVNBQ1FRTjJkQ0lDY1VVRVFFR0lIeUFCSUFKeU5nSUFJQUFNQVFzZ0FDZ0NDQXNoQVNBQUlBTTJBZ2dnQVNBRE5nSU1JQU1nQURZQ0RDQURJQUUyQWdnTUFRdEJIeUVBSUFKQi8vLy9CMDBFUUNBQ1FTWWdBa0VJZG1jaUFHdDJRUUZ4SUFCQkFYUnJRVDVxSVFBTElBTWdBRFlDSENBRFFnQTNBaEFnQUVFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUJFRUJJQUIwSWdaeFJRUkFRWXdmSUFRZ0JuSTJBZ0FnQVNBRE5nSUFEQUVMSUFKQkdTQUFRUUYyYTBFQUlBQkJIMGNiZENFQUlBRW9BZ0FoQkFOQUlBUWlBU2dDQkVGNGNTQUNSZzBDSUFCQkhYWWhCQ0FBUVFGMElRQWdBU0FFUVFSeGFpSUdLQUlRSWdRTkFBc2dCaUFETmdJUUN5QURJQUUyQWhnZ0F5QUROZ0lNSUFNZ0F6WUNDQXdCQ3lBQktBSUlJZ0FnQXpZQ0RDQUJJQU0yQWdnZ0EwRUFOZ0lZSUFNZ0FUWUNEQ0FESUFBMkFnZ0xRWlFmS0FJQUlnQWdCVTBOQUVHVUh5QUFJQVZySWdFMkFnQkJvQjlCb0I4b0FnQWlBQ0FGYWlJQ05nSUFJQUlnQVVFQmNqWUNCQ0FBSUFWQkEzSTJBZ1FnQUVFSWFpRUFEQWdMUVlRZlFUQTJBZ0JCQUNFQURBY0xRUUFoQWdzZ0NFVU5BQUpBSUFZb0Fod2lBVUVDZEVHNElXb2lCQ2dDQUNBR1JnUkFJQVFnQWpZQ0FDQUNEUUZCakI5QmpCOG9BZ0JCZmlBQmQzRTJBZ0FNQWdzZ0NFRVFRUlFnQ0NnQ0VDQUdSaHRxSUFJMkFnQWdBa1VOQVFzZ0FpQUlOZ0lZSUFZb0FoQWlBUVJBSUFJZ0FUWUNFQ0FCSUFJMkFoZ0xJQVlvQWhRaUFVVU5BQ0FDSUFFMkFoUWdBU0FDTmdJWUN5QUFJQWxxSVFBZ0JpQUphaUlHS0FJRUlRTUxJQVlnQTBGK2NUWUNCQ0FGSUFCQkFYSTJBZ1FnQUNBRmFpQUFOZ0lBSUFCQi93Rk5CRUFnQUVGNGNVR3dIMm9oQVFKL1FZZ2ZLQUlBSWdKQkFTQUFRUU4yZENJQWNVVUVRRUdJSHlBQUlBSnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEFDQUJJQVUyQWdnZ0FDQUZOZ0lNSUFVZ0FUWUNEQ0FGSUFBMkFnZ01BUXRCSHlFRElBQkIvLy8vQjAwRVFDQUFRU1lnQUVFSWRtY2lBV3QyUVFGeElBRkJBWFJyUVQ1cUlRTUxJQVVnQXpZQ0hDQUZRZ0EzQWhBZ0EwRUNkRUc0SVdvaEFRSkFBa0JCakI4b0FnQWlBa0VCSUFOMElnUnhSUVJBUVl3ZklBSWdCSEkyQWdBZ0FTQUZOZ0lBREFFTElBQkJHU0FEUVFGMmEwRUFJQU5CSDBjYmRDRURJQUVvQWdBaEFnTkFJQUlpQVNnQ0JFRjRjU0FBUmcwQ0lBTkJIWFloQWlBRFFRRjBJUU1nQVNBQ1FRUnhhaUlFS0FJUUlnSU5BQXNnQkNBRk5nSVFDeUFGSUFFMkFoZ2dCU0FGTmdJTUlBVWdCVFlDQ0F3QkN5QUJLQUlJSWdBZ0JUWUNEQ0FCSUFVMkFnZ2dCVUVBTmdJWUlBVWdBVFlDRENBRklBQTJBZ2dMSUFkQkNHb2hBQXdDQ3dKQUlBZEZEUUFDUUNBRUtBSWNJZ0JCQW5SQnVDRnFJZ0VvQWdBZ0JFWUVRQ0FCSUFJMkFnQWdBZzBCUVl3ZklBaEJmaUFBZDNFaUNEWUNBQXdDQ3lBSFFSQkJGQ0FIS0FJUUlBUkdHMm9nQWpZQ0FDQUNSUTBCQ3lBQ0lBYzJBaGdnQkNnQ0VDSUFCRUFnQWlBQU5nSVFJQUFnQWpZQ0dBc2dCQ2dDRkNJQVJRMEFJQUlnQURZQ0ZDQUFJQUkyQWhnTEFrQWdBMEVQVFFSQUlBUWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0JHb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBUWdCVUVEY2pZQ0JDQUVJQVZxSWdJZ0EwRUJjallDQkNBQ0lBTnFJQU0yQWdBZ0EwSC9BVTBFUUNBRFFYaHhRYkFmYWlFQUFuOUJpQjhvQWdBaUFVRUJJQU5CQTNaMElnTnhSUVJBUVlnZklBRWdBM0kyQWdBZ0FBd0JDeUFBS0FJSUN5RUJJQUFnQWpZQ0NDQUJJQUkyQWd3Z0FpQUFOZ0lNSUFJZ0FUWUNDQXdCQzBFZklRQWdBMEgvLy84SFRRUkFJQU5CSmlBRFFRaDJaeUlBYTNaQkFYRWdBRUVCZEd0QlBtb2hBQXNnQWlBQU5nSWNJQUpDQURjQ0VDQUFRUUowUWJnaGFpRUJBa0FDUUNBSVFRRWdBSFFpQm5GRkJFQkJqQjhnQmlBSWNqWUNBQ0FCSUFJMkFnQU1BUXNnQTBFWklBQkJBWFpyUVFBZ0FFRWZSeHQwSVFBZ0FTZ0NBQ0VGQTBBZ0JTSUJLQUlFUVhoeElBTkdEUUlnQUVFZGRpRUdJQUJCQVhRaEFDQUJJQVpCQkhGcUlnWW9BaEFpQlEwQUN5QUdJQUkyQWhBTElBSWdBVFlDR0NBQ0lBSTJBZ3dnQWlBQ05nSUlEQUVMSUFFb0FnZ2lBQ0FDTmdJTUlBRWdBallDQ0NBQ1FRQTJBaGdnQWlBQk5nSU1JQUlnQURZQ0NBc2dCRUVJYWlFQURBRUxBa0FnQ1VVTkFBSkFJQUlvQWh3aUFFRUNkRUc0SVdvaUFTZ0NBQ0FDUmdSQUlBRWdCRFlDQUNBRURRRkJqQjhnQzBGK0lBQjNjVFlDQUF3Q0N5QUpRUkJCRkNBSktBSVFJQUpHRzJvZ0JEWUNBQ0FFUlEwQkN5QUVJQWsyQWhnZ0FpZ0NFQ0lBQkVBZ0JDQUFOZ0lRSUFBZ0JEWUNHQXNnQWlnQ0ZDSUFSUTBBSUFRZ0FEWUNGQ0FBSUFRMkFoZ0xBa0FnQTBFUFRRUkFJQUlnQXlBRmFpSUFRUU55TmdJRUlBQWdBbW9pQUNBQUtBSUVRUUZ5TmdJRURBRUxJQUlnQlVFRGNqWUNCQ0FDSUFWcUlnUWdBMEVCY2pZQ0JDQURJQVJxSUFNMkFnQWdCd1JBSUFkQmVIRkJzQjlxSVFCQm5COG9BZ0FoQVFKL1FRRWdCMEVEZG5RaUJTQUdjVVVFUUVHSUh5QUZJQVp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hCaUFBSUFFMkFnZ2dCaUFCTmdJTUlBRWdBRFlDRENBQklBWTJBZ2dMUVp3ZklBUTJBZ0JCa0I4Z0F6WUNBQXNnQWtFSWFpRUFDeUFLUVJCcUpBQWdBQXZTQ3dFSGZ3SkFJQUJGRFFBZ0FFRUlheUlDSUFCQkJHc29BZ0FpQVVGNGNTSUFhaUVGQWtBZ0FVRUJjUTBBSUFGQkEzRkZEUUVnQWlBQ0tBSUFJZ0ZySWdKQm1COG9BZ0JKRFFFZ0FDQUJhaUVBQWtBQ1FFR2NIeWdDQUNBQ1J3UkFJQUZCL3dGTkJFQWdBVUVEZGlFRUlBSW9BZ3dpQVNBQ0tBSUlJZ05HQkVCQmlCOUJpQjhvQWdCQmZpQUVkM0UyQWdBTUJRc2dBeUFCTmdJTUlBRWdBellDQ0F3RUN5QUNLQUlZSVFZZ0FpQUNLQUlNSWdGSEJFQWdBaWdDQ0NJRElBRTJBZ3dnQVNBRE5nSUlEQU1MSUFKQkZHb2lCQ2dDQUNJRFJRUkFJQUlvQWhBaUEwVU5BaUFDUVJCcUlRUUxBMEFnQkNFSElBTWlBVUVVYWlJRUtBSUFJZ01OQUNBQlFSQnFJUVFnQVNnQ0VDSUREUUFMSUFkQkFEWUNBQXdDQ3lBRktBSUVJZ0ZCQTNGQkEwY05Ba0dRSHlBQU5nSUFJQVVnQVVGK2NUWUNCQ0FDSUFCQkFYSTJBZ1FnQlNBQU5nSUFEd3RCQUNFQkN5QUdSUTBBQWtBZ0FpZ0NIQ0lEUVFKMFFiZ2hhaUlFS0FJQUlBSkdCRUFnQkNBQk5nSUFJQUVOQVVHTUgwR01IeWdDQUVGK0lBTjNjVFlDQUF3Q0N5QUdRUkJCRkNBR0tBSVFJQUpHRzJvZ0FUWUNBQ0FCUlEwQkN5QUJJQVkyQWhnZ0FpZ0NFQ0lEQkVBZ0FTQUROZ0lRSUFNZ0FUWUNHQXNnQWlnQ0ZDSURSUTBBSUFFZ0F6WUNGQ0FESUFFMkFoZ0xJQUlnQlU4TkFDQUZLQUlFSWdGQkFYRkZEUUFDUUFKQUFrQUNRQ0FCUVFKeFJRUkFRYUFmS0FJQUlBVkdCRUJCb0I4Z0FqWUNBRUdVSDBHVUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FDUVp3ZktBSUFSdzBHUVpBZlFRQTJBZ0JCbkI5QkFEWUNBQThMUVp3ZktBSUFJQVZHQkVCQm5COGdBallDQUVHUUgwR1FIeWdDQUNBQWFpSUFOZ0lBSUFJZ0FFRUJjallDQkNBQUlBSnFJQUEyQWdBUEN5QUJRWGh4SUFCcUlRQWdBVUgvQVUwRVFDQUJRUU4ySVFRZ0JTZ0NEQ0lCSUFVb0FnZ2lBMFlFUUVHSUgwR0lIeWdDQUVGK0lBUjNjVFlDQUF3RkN5QURJQUUyQWd3Z0FTQUROZ0lJREFRTElBVW9BaGdoQmlBRklBVW9BZ3dpQVVjRVFFR1lIeWdDQUJvZ0JTZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQVZCRkdvaUJDZ0NBQ0lEUlFSQUlBVW9BaEFpQTBVTkFpQUZRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGSUFGQmZuRTJBZ1FnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUF3REMwRUFJUUVMSUFaRkRRQUNRQ0FGS0FJY0lnTkJBblJCdUNGcUlnUW9BZ0FnQlVZRVFDQUVJQUUyQWdBZ0FRMEJRWXdmUVl3ZktBSUFRWDRnQTNkeE5nSUFEQUlMSUFaQkVFRVVJQVlvQWhBZ0JVWWJhaUFCTmdJQUlBRkZEUUVMSUFFZ0JqWUNHQ0FGS0FJUUlnTUVRQ0FCSUFNMkFoQWdBeUFCTmdJWUN5QUZLQUlVSWdORkRRQWdBU0FETmdJVUlBTWdBVFlDR0FzZ0FpQUFRUUZ5TmdJRUlBQWdBbW9nQURZQ0FDQUNRWndmS0FJQVJ3MEFRWkFmSUFBMkFnQVBDeUFBUWY4QlRRUkFJQUJCZUhGQnNCOXFJUUVDZjBHSUh5Z0NBQ0lEUVFFZ0FFRURkblFpQUhGRkJFQkJpQjhnQUNBRGNqWUNBQ0FCREFFTElBRW9BZ2dMSVFBZ0FTQUNOZ0lJSUFBZ0FqWUNEQ0FDSUFFMkFnd2dBaUFBTmdJSUR3dEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBSWdBellDSENBQ1FnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQUNRRUdNSHlnQ0FDSUVRUUVnQTNRaUIzRkZCRUJCakI4Z0JDQUhjallDQUNBQklBSTJBZ0FnQWlBQk5nSVlEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQVFOQUlBRWlCQ2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBU0FEUVFGMElRTWdCQ0FCUVFSeGFpSUhRUkJxS0FJQUlnRU5BQXNnQnlBQ05nSVFJQUlnQkRZQ0dBc2dBaUFDTmdJTUlBSWdBallDQ0F3QkN5QUVLQUlJSWdBZ0FqWUNEQ0FFSUFJMkFnZ2dBa0VBTmdJWUlBSWdCRFlDRENBQ0lBQTJBZ2dMUWFnZlFhZ2ZLQUlBUVFGcklnQkJmeUFBR3pZQ0FBc0xCQUFqQUFzR0FDQUFKQUFMRUFBakFDQUFhMEZ3Y1NJQUpBQWdBQXRLQVFGL0lBQWdBVWtFUUNBQUlBRWdBaEFDRHdzZ0FnUkFJQUFnQW1vaEF5QUJJQUpxSVFFRFFDQURRUUZySWdNZ0FVRUJheUlCTFFBQU9nQUFJQUpCQVdzaUFnMEFDd3NnQUF2OURnSVJmd0YrSXdCQk1Hc2lCeVFBUWJoL0lRZ0NRQ0FGUlEwQUlBUXNBQUFpQ1VIL0FYRWhDd0pBSUFsQkFFZ0VRQ0FMUWY0QWEwRUJkaUlHSUFWUERRSkJiQ0VJSUF0Qi93QnJJZ3RCL3dGTERRSWdCRUVCYWlFSVFRQWhCUU5BSUFVZ0MwOEVRQ0FMSVFnZ0JpRUxEQU1GSUFBZ0JXb2dDQ0FGUVFGMmFpSUVMUUFBUVFSMk9nQUFJQUFnQlVFQmNtb2dCQzBBQUVFUGNUb0FBQ0FGUVFKcUlRVU1BUXNBQ3dBTElBVWdDMDBOQVNBSFFmOEJOZ0lFSUFZZ0IwRUVhaUFIUVFocUlBUkJBV29pRGlBTEVBd2lCRUdJZjBzRVFDQUVJUWdNQWd0QlZDRUlJQWNvQWdnaUVFRUdTdzBCSUFjb0FnUWlFVUVCZENJSlFRSnFyVUlCSUJDdGhpSVlRUUVnRUhRaURVRUJhaUlGclVJQ2hueDhRZ3Q4UXZ6Ly8vLy8vLy8vL3dDRFF1UUNWZzBCUVZJaENDQVJRZjhCU3cwQklBMUJmM05CQW5SQjVBSnFyU0FSUVFGcUloVkJBWFN0SUJoOFFnaDhWQTBCSUFzZ0JHc2hGaUFFSUE1cUlSY2dCa0dBQkdvaUVpQUZRUUowYWlJUklBbHFRUUpxSVE0Z0JrR0VCR29oRTBHQWdBSWdFSFJCRUhZaENVRUFJUVZCQVNFUElBMUJBV3NpRkNFS0EwQWdCU0FWUmtVRVFBSkFJQVlnQlVFQmRDSUlhaThCQUNJRVFmLy9BMFlFUUNBVElBcEJBblJxSUFVNkFBSWdDa0VCYXlFS1FRRWhCQXdCQ3lBUFFRQWdDU0FFd1VvYklROExJQWdnRVdvZ0JEc0JBQ0FGUVFGcUlRVU1BUXNMSUFZZ0R6c0JnZ1FnQmlBUU93R0FCQUpBSUFvZ0ZFWUVRQ0FOUVFOMklRaENBQ0VZUVFBaER3TkFJQXdnRlVZRVFDQUlJQTFCQVhacVFRTnFJZ2xCQVhRaENFRUFJUVJCQUNFS0EwQkJBQ0VGSUFvZ0RVOE5CQU5BSUFWQkFrWkZCRUFnRXlBRklBbHNJQVJxSUJSeFFRSjBhaUFPSUFVZ0NtcHFMUUFBT2dBQ0lBVkJBV29oQlF3QkN3c2dDa0VDYWlFS0lBUWdDR29nRkhFaEJBd0FDd0FGSUFZZ0RFRUJkR291QVFBaENTQU9JQTlxSWdRZ0dEY0FBRUVJSVFVRFFDQUZJQWxPUlFSQUlBUWdCV29nR0RjQUFDQUZRUWhxSVFVTUFRc0xJQmhDZ1lLRWlKQ2d3SUFCZkNFWUlBeEJBV29oRENBSklBOXFJUThNQVFzQUN3QUxJQTFCQTNZZ0RVRUJkbXBCQTJvaENFRUFJUVVEUUNBTUlCVkdSUVJBUVFBaENTQUdJQXhCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQUpSa1VFUUNBVElBVkJBblJxSUF3NkFBSURRQ0FGSUFocUlCUnhJZ1VnQ2tzTkFBc2dDVUVCYWlFSkRBRUxDeUFNUVFGcUlRd01BUXNMUVg4aENDQUZEUUlMSUJCQkFXb2hDRUVBSVFVRFFDQUZJQTFHUlFSQUlCRWdFeUFGUVFKMGFpSU9MUUFDUVFGMGFpSUVJQVF2QVFBaUNVRUJhanNCQUNBT0lBZ2dDV2RCWUhOcUlnUTZBQU1nRGlBSklBUjBJQTFyT3dFQUlBVkJBV29oQlF3QkN3c0NRQUpBSUFZdkFZSUVCRUFnQjBFY2FpSUVJQmNnRmhBTklnaEJpSDlMRFFJZ0IwRVVhaUFFSUJJUURpQUhRUXhxSUFRZ0VoQU9RUUFoQlFOQUlBZEJIR29pQkJBUElBVkIrd0ZMY2cwQ0lBQWdCV29pQmlBSFFSUnFJQVFRRURvQUFDQUdJQWRCREdvZ0JCQVFPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVTUF3VWdBQ0FFYWlBSFFSUnFJQWRCSEdvaUJCQVFPZ0FBSUFZZ0IwRU1haUFFRUJBNkFBTWdCVUVFYWlFRkRBRUxBQXNBQ3lBSFFSeHFJZ1FnRnlBV0VBMGlDRUdJZjBzTkFTQUhRUlJxSUFRZ0VoQU9JQWRCREdvZ0JDQVNFQTVCQUNFRkEwQWdCMEVjYWlJRUVBOGdCVUg3QVV0eVJRUkFJQUFnQldvaUJpQUhRUlJxSUFRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBQklBVkJBbkloQkNBSFFSeHFFQThFUUNBRUlRVUZJQUFnQkdvZ0IwRVVhaUFIUVJ4cUlnUVFFVG9BQUNBR0lBZEJER29nQkJBUk9nQURJQVZCQkdvaEJRd0NDd3NMQW44RFFFRzZmeUVJSUFWQi9RRkxEUU1nQUNBRmFpSUdJQWRCRkdvZ0IwRWNhaUlKRUJFNkFBQWdCa0VCYWlFRUlBa1FEMEVEUmdSQUlBZEJER29oQ0VFQ0RBSUxJQVZCL0FGTERRTWdCaUFIUVF4cUlBZEJIR29pQkJBUk9nQUJJQVZCQW1vaEJTQUVFQTlCQTBjTkFBc2dBQ0FGYWlFRUlBZEJGR29oQ0VFREN5QUVJQWdnQjBFY2FoQVJPZ0FBSUFacUlBQnJJUWdNQVFzQ2Z3TkFRYnAvSVFnZ0JVSDlBVXNOQWlBQUlBVnFJZ1lnQjBFVWFpQUhRUnhxSWdrUUVEb0FBQ0FHUVFGcUlRUWdDUkFQUVFOR0JFQWdCMEVNYWlFSVFRSU1BZ3NnQlVIOEFVc05BaUFHSUFkQkRHb2dCMEVjYWlJRUVCQTZBQUVnQlVFQ2FpRUZJQVFRRDBFRFJ3MEFDeUFBSUFWcUlRUWdCMEVVYWlFSVFRTUxJQVFnQ0NBSFFSeHFFQkE2QUFBZ0Jtb2dBR3NoQ0FzZ0NFR0lmMHNOQVFzZ0NDRUVRUUFoQlNBQlFRQkJOQkFESVFsQkFDRUtBMEFnQkNBRlJ3UkFJQUFnQldvaUJpMEFBQ0lCUVF0TEJFQkJiQ0VJREFNRklBa2dBVUVDZEdvaUFTQUJLQUlBUVFGcU5nSUFJQVZCQVdvaEJVRUJJQVl0QUFCMFFRRjFJQXBxSVFvTUFnc0FDd3RCYkNFSUlBcEZEUUFnQ21jaUJVRWZjeUlCUVF0TERRQWdBMEVnSUFWck5nSUFRUUZCQWlBQmRDQUtheUlEWjBFZmN5SUJkQ0FEUncwQUlBQWdCR29nQVVFQmFpSUFPZ0FBSUFrZ0FFRUNkR29pQUNBQUtBSUFRUUZxTmdJQUlBa29BZ1FpQUVFQ1NTQUFRUUZ4Y2cwQUlBSWdCRUVCYWpZQ0FDQUxRUUZxSVFnTElBZEJNR29rQUNBSUM2QUZBUXgvSXdCQkVHc2lEQ1FBQW44Z0JFRUhUUVJBSUF4Q0FEY0RDQ0FNUVFocUlnVWdBeUFFRUFJYVFXd2dBQ0FCSUFJZ0JVRUlFQXdpQUNBQUlBUkxHeUFBSUFCQmlYOUpHd3dCQ3lBQVFRQWdBU2dDQUVFQmFpSU5RUUYwRUFNaEQwRlVJQU1vQUFBaUJrRVBjU0lBUVFwTERRQWFJQUlnQUVFRmFqWUNBQ0FESUFScUlnSkJCR3NoQnlBQ1FRZHJJUXNnQUVFR2FpRU9RUVFoQWlBR1FRUjJJUVZCSUNBQWRDSUlRUUZ5SVFsQkFDRUFRUUVoQmlBRElRUURRQUpBSUFaQkFYRkZCRUFEUUNBRlFYOXpRWUNBZ0lCNGNtZ2lCa0VZU1VVRVFDQUFRU1JxSVFBZ0JDQUxUUVIvSUFSQkEyb0ZJQVFnQzJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVNQVFzTElBSWdCa0VlY1NJS2FrRUNhaUVDSUFaQkFYWkJBMndnQUdvZ0JTQUtka0VEY1dvaUFDQU5UdzBCQW44Z0JDQUxTeUFDUVFOMklBUnFJZ1VnQjB0eFJRUkFJQUpCQjNFaEFpQUZEQUVMSUFRZ0IydEJBM1FnQW1wQkgzRWhBaUFIQ3lJRUtBQUFJQUoySVFVTElBVWdDRUVCYTNFaUJpQUlRUUYwUVFGcklnb2dDV3NpRUVrRWZ5QU9RUUZyQlNBRklBcHhJZ1VnRUVFQUlBVWdDRTRiYXlFR0lBNExJUVVnRHlBQVFRRjBhaUFHUVFGcklnbzdBUUFnQUVFQmFpRUFJQUlnQldvaEFpQUlRUUVnQm1zZ0NpQUdRUUJLR3lBSmFpSUpTZ1JBSUFsQkFrZ05BVUVnSUFsbklnVnJJUTVCQVNBRlFSOXpkQ0VJQ3lBQUlBMVBEUUFnQ2tFQVJ5RUdBbjhnQkNBTFN5QUNRUU4xSUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQUlnQkNBSGEwRURkR3BCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVNQVFzTFFXd2dDVUVCUncwQUdrRlFJQUFnRFVzTkFCcEJiQ0FDUVNCS0RRQWFJQUVnQUVFQmF6WUNBQ0FFSUFKQkIycEJBM1ZxSUFOckN5QU1RUkJxSkFBTDhnRUJBWDhnQWtVRVFDQUFRZ0EzQWdBZ0FFRUFOZ0lRSUFCQ0FEY0NDRUc0Znc4TElBQWdBVFlDRENBQUlBRkJCR28yQWhBZ0FrRUVUd1JBSUFBZ0FTQUNhaUlCUVFScklnTTJBZ2dnQUNBREtBQUFOZ0lBSUFGQkFXc3RBQUFpQVFSQUlBQWdBV2RCRjJzMkFnUWdBZzhMSUFCQkFEWUNCRUYvRHdzZ0FDQUJOZ0lJSUFBZ0FTMEFBQ0lETmdJQUFrQUNRQUpBSUFKQkFtc09BZ0VBQWdzZ0FDQUJMUUFDUVJCMElBTnlJZ00yQWdBTElBQWdBUzBBQVVFSWRDQURhallDQUFzZ0FTQUNha0VCYXkwQUFDSUJSUVJBSUFCQkFEWUNCRUZzRHdzZ0FDQUJaeUFDUVFOMGEwRUphallDQkNBQ0MwUUJBbjhnQVNBQ0x3RUFJZ01nQVNnQ0JHb2lCRFlDQkNBQUlBTkJBblJCb0IxcUtBSUFJQUVvQWdCQkFDQUVhM1p4TmdJQUlBRVFEeG9nQUNBQ1FRUnFOZ0lFQzU4QkFRUi9RUU1oQVNBQUtBSUVJZ0pCSUUwRVFDQUFLQUlJSWdFZ0FDZ0NFRThFUUNBQUlBSkJCM0UyQWdRZ0FDQUJJQUpCQTNacklnSTJBZ2dnQUNBQ0tBQUFOZ0lBUVFBUEN5QUFLQUlNSWdNZ0FVWUVRRUVCUVFJZ0FrRWdTUnNQQ3lBQUlBRWdBU0FEYXlBQ1FRTjJJZ1FnQVNBRWF5QURTU0lCR3lJRGF5SUVOZ0lJSUFBZ0FpQURRUU4wYXpZQ0JDQUFJQVFvQUFBMkFnQUxJQUVMU0FFRWZ5QUFLQUlFSUFBb0FnQkJBblJxSWdJdEFBSWdBaThCQUNFRUlBRWdBU2dDQkNJRklBSXRBQU1pQW1vMkFnUWdBQ0FFSUFFb0FnQWdCWFJCQUNBQ2EzWnFOZ0lBQzFJQkJIOGdBQ2dDQkNBQUtBSUFRUUowYWlJQ0xRQUNJQUl2QVFBaEJDQUJJQUl0QUFNaUFpQUJLQUlFYWlJRk5nSUVJQUFnQkNBQ1FRSjBRYUFkYWlnQ0FDQUJLQUlBUVFBZ0JXdDJjV28yQWdBTENBQWdBRUdJZjBzTEdnQWdBQVJBSUFFRVFDQUNJQUFnQVJFQ0FBOExJQUFRQmdzTHBnZ0NEWDhCZmlNQVFSQnJJZ2trQUNBSlFRQTJBZ3dnQ1VFQU5nSUlBbjhDUUNBRFFlZ0phaUFESUFsQkNHb2dDVUVNYWlBQklBSWdBMEdBQVdvUUN5SVBRWWgvU3cwQVFWUWdDU2dDRENJRUlBQW9BZ0FpQVVIL0FYRkJBV3BMRFFFYUlBQkJCR29oQ3lBQUlBRkIvNEdBZUhFZ0JFRVFkRUdBZ1B3SGNYSTJBZ0JCZnlBRUlBUkJBRWdiUVFGcUlRQkJBQ0VCSUFrb0FnZ2hCVUVBSVFJRFFDQUFJQUpHQkVBZ0JVRURheUVCUVFBaEFBTkFBa0JCQUNFQ0lBQWdBVTRFUUFOQUlBQWdCVTROQWlBRElBQWdBMnBCNkFscUxRQUFRUUowYWtGQWF5SUJJQUVvQWdBaUFVRUJhallDQUNBQklBTnFJQUE2QU9nSElBQkJBV29oQUF3QUN3QUZBMEFnQWtFRVJrVUVRQ0FESUFNZ0FDQUNhaUlIYWtIb0NXb3RBQUJCQW5ScVFVQnJJZ2dnQ0NnQ0FDSUlRUUZxTmdJQUlBTWdDR29nQnpvQTZBY2dBa0VCYWlFQ0RBRUxDeUFBUVFScUlRQU1BZ3NBQ3dzZ0JFRUJhaUVPSUFNb0FnQWhCMEVBSVFCQkFTRUlBMEFnQ0NBT1JnMERJQTRnQ0dzaEJDQURJQWhCQW5ScUtBSUFJUVVDUUFKQUFrQUNRQUpBQWtCQkFTQUlkRUVCZFNJTlFRRnJEZ2dBQVFRQ0JBUUVBd1FMUVFBaEFpQUZRUUFnQlVFQVNoc2hCaUFBSVFFRFFDQUNJQVpHRFFVZ0F5QUNJQWRxYWkwQTZBY2hDaUFMSUFGQkFYUnFJZ3dnQkRvQUFTQU1JQW82QUFBZ0FrRUJhaUVDSUFGQkFXb2hBUXdBQ3dBTFFRQWhBaUFGUVFBZ0JVRUFTaHNoQ2lBQUlRRURRQ0FDSUFwR0RRUWdDeUFCUVFGMGFpSUdJQU1nQWlBSGFtb3RBT2dISWd3NkFBSWdCaUFFT2dBQklBWWdERG9BQUNBR0lBUTZBQU1nQWtFQmFpRUNJQUZCQW1vaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hCaUFFUVFoMFFZRCtBM0VoQkNBQUlRRURRQ0FDSUFaR0RRTWdDeUFCUVFGMGFpQUVJQU1nQWlBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK053QUFJQUpCQVdvaEFpQUJRUVJxSVFFTUFBc0FDMEVBSVFJZ0JVRUFJQVZCQUVvYklRWWdCRUVJZEVHQS9nTnhJUVFnQUNFQkEwQWdBaUFHUmcwQ0lBc2dBVUVCZEdvaUNpQUVJQU1nQWlBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK0loRTNBQWdnQ2lBUk53QUFJQUpCQVdvaEFpQUJRUWhxSVFFTUFBc0FDMEVBSVFFZ0JVRUFJQVZCQUVvYklRb2dCRUVJZEVHQS9nTnhJUXdnQUNFRUEwQWdBU0FLUmcwQklBc2dCRUVCZEdvaEVDQU1JQU1nQVNBSGFtb3RBT2dIY3ExQ2dZQ0VnSkNBd0FCK0lSRkJBQ0VDQTBBZ0FpQU5Ua1VFUUNBUUlBSkJBWFJxSWdZZ0VUY0FHQ0FHSUJFM0FCQWdCaUFSTndBSUlBWWdFVGNBQUNBQ1FSQnFJUUlNQVFzTElBRkJBV29oQVNBRUlBMXFJUVFNQUFzQUN5QUlRUUZxSVFnZ0JTQUhhaUVISUFVZ0RXd2dBR29oQUF3QUN3QUZJQU1nQWtFQ2RHb2lCMEZBYXlBQk5nSUFJQUpCQVdvaEFpQUhLQUlBSUFGcUlRRU1BUXNBQ3dBTElBOExJQWxCRUdva0FBdnlBZ0VHZnlNQVFTQnJJZ1VrQUNBRUtBSUFJUVlnQlVFTWFpQUNJQU1RRFNJRFFZaC9UUVJBSUFSQkJHb2hBaUFBSUFGcUlnbEJBMnNoQkVFQUlBWkJFSFpyUVI5eElRTURRQ0FGUVF4cUVBOGdBQ0FFVDNKRkJFQWdBaUFGS0FJTUlnWWdCU2dDRUNJSGRDQURka0VCZEdvaUNDMEFBU0VLSUFBZ0NDMEFBRG9BQUNBQ0lBWWdCeUFLYWlJR2RDQURka0VCZEdvaUJ5MEFBQ0VJSUFVZ0JpQUhMUUFCYWpZQ0VDQUFJQWc2QUFFZ0FFRUNhaUVBREFFTEN3TkFJQVZCREdvUUR5RUhJQVVvQWd3aEJpQUZLQUlRSVFRZ0FDQUpUeUFIY2tVRVFDQUNJQVlnQkhRZ0EzWkJBWFJxSWdZdEFBQWhCeUFGSUFRZ0JpMEFBV28yQWhBZ0FDQUhPZ0FBSUFCQkFXb2hBQXdCQ3dzRFFDQUFJQWxQUlFSQUlBSWdCaUFFZENBRGRrRUJkR29pQnkwQUFTRUlJQUFnQnkwQUFEb0FBQ0FBUVFGcUlRQWdCQ0FJYWlFRURBRUxDMEZzUVd3Z0FTQUZLQUlVSUFVb0FoaEhHeUFFUVNCSEd5RURDeUFGUVNCcUpBQWdBd3ZQRkFFamZ5TUFRZEFBYXlJRkpBQkJiQ0VKQWtBZ0EwRUtTUTBBQWtBZ0F5QUNMd0FFSWdjZ0FpOEFBQ0lJSUFJdkFBSWlEV3BxUVFacUlneEpEUUFnQkM4QkFpRUdJQVZCUEdvZ0FrRUdhaUlDSUFnUURTSUpRWWgvU3cwQklBVkJLR29nQWlBSWFpSUNJQTBRRFNJSlFZaC9TdzBCSUFWQkZHb2dBaUFOYWlJQ0lBY1FEU0lKUVloL1N3MEJJQVVnQWlBSGFpQURJQXhyRUEwaUNVR0lmMHNOQVNBRVFRUnFJUW9nQUNBQmFpSWZRUU5ySVNCQkFDQUdhMEVmY1NFTElBVW9BZ2doRVNBRktBSWNJUklnQlNnQ01DRVRJQVVvQWtRaEZDQUZLQUlFSVFrZ0JTZ0NHQ0VOSUFVb0Fpd2hEQ0FGS0FKQUlRWWdCU2dDRUNFaElBVW9BaVFoSWlBRktBSTRJU01nQlNnQ1RDRWtJQVVvQWdBaEZTQUZLQUlVSVJZZ0JTZ0NLQ0VYSUFVb0Fqd2hHRUVCSVE4Z0FDQUJRUU5xUVFKMklnUnFJZ01nQkdvaUFpQUVhaUlaSVFRZ0FpRUlJQU1oQndOQUlBOUJBWEZGSUFRZ0lFOXlSUVJBSUFBZ0NpQVlJQVowSUF0MlFRSjBhaUlPTHdFQU93QUFJQTR0QUFJaEdpQU9MUUFESVJBZ0J5QUtJQmNnREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnRGkwQUFpRWJJQTR0QUFNaER5QUlJQW9nRmlBTmRDQUxka0VDZEdvaURpOEJBRHNBQUNBT0xRQUNJUndnRGkwQUF5RWRJQVFnQ2lBVklBbDBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloSGlBT0xRQURJUTRnQUNBUWFpSWxJQW9nR0NBR0lCcHFJZ1owSUF0MlFRSjBhaUlRTHdFQU93QUFJQkF0QUFJZ0VDMEFBeUVtSUFjZ0Qyb2lKeUFLSUJjZ0RDQWJhaUlhZENBTGRrRUNkR29pQnk4QkFEc0FBQ0FITFFBQ0lRd2dCeTBBQXlFUUlBZ2dIV29pR3lBS0lCWWdEU0FjYWlJUGRDQUxka0VDZEdvaUNDOEJBRHNBQUNBSUxRQUNJUTBnQ0MwQUF5RWNJQVFnRG1vaUhTQUtJQlVnQ1NBZWFpSU9kQ0FMZGtFQ2RHb2lDUzhCQURzQUFDQUdhaUVBUVFNaEJ3Si9JQlFnSkVrRVFDQUFJUVpCQXd3QkN5QUFRUWR4SVFZZ0ZDQUFRUU4yYXlJVUtBQUFJUmhCQUFzZ0NTMEFBeUVlSUFrdEFBSWhDQ0FNSUJwcUlRQWdFeUFqU1FSL0lBQUZJQk1nQUVFRGRtc2lFeWdBQUNFWFFRQWhCeUFBUVFkeEN5RU1JQTBnRDJvaEFDQUhjaUVKUVFNaER3Si9JQklnSWtrRVFDQUFJUTFCQXd3QkN5QUFRUWR4SVEwZ0VpQUFRUU4yYXlJU0tBQUFJUlpCQUFzZ0NDQU9haUVBSUFseUlCRWdJVWtFZnlBQUJTQVJJQUJCQTNackloRW9BQUFoRlVFQUlROGdBRUVIY1FzaENTQWxJQ1pxSVFBZ0VDQW5haUVISUJzZ0hHb2hDQ0FkSUI1cUlRUWdEM0pGSVE4TUFRc0xJQVVnRERZQ0xDQUZJQVkyQWtBZ0JTQU5OZ0lZSUFVZ0NUWUNCQ0FGSUJRMkFrUWdCU0FUTmdJd0lBVWdFallDSENBRklCRTJBZ2dnQlNBWU5nSThJQVVnRnpZQ0tDQUZJQlkyQWhRZ0JTQVZOZ0lBSUFJZ0Iwa2dBQ0FEUzNJTkFFRnNJUWtnQ0NBWlN3MEJJQU5CQTJzaENRTkFJQVZCUEdvUUQwVWdBQ0FKU1hFRVFDQUFJQW9nQlNnQ1BDSU5JQVVvQWtBaURIUWdDM1pCQW5ScUlnNHZBUUE3QUFBZ0FDQU9MUUFEYWlJR0lBb2dEU0FNSUE0dEFBSnFJZ0IwSUF0MlFRSjBhaUlNTHdFQU93QUFJQVVnQUNBTUxRQUNhallDUUNBR0lBd3RBQU5xSVFBTUFRVWdBMEVDYXlFTUEwQWdCVUU4YWhBUElRWWdCU2dDUENFTklBVW9Ba0FoQ1NBQUlBeExJQVp5UlFSQUlBQWdDaUFOSUFsMElBdDJRUUowYWlJR0x3RUFPd0FBSUFVZ0NTQUdMUUFDYWpZQ1FDQUFJQVl0QUFOcUlRQU1BUXNMQTBBZ0FDQU1TMFVFUUNBQUlBb2dEU0FKZENBTGRrRUNkR29pQmk4QkFEc0FBQ0FBSUFZdEFBTnFJUUFnQ1NBR0xRQUNhaUVKREFFTEN3SkFJQUFnQTA4TkFDQUFJQW9nRFNBSmRDQUxkaUlBUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUpJQU10QUFKcUlRa01BUXNnQ1VFZlN3MEFRU0FnQ1NBS0lBQkJBblJxTFFBQ2FpSUFJQUJCSUU4YklRa0xJQUpCQTJzaERBTkFJQVZCS0dvUUQwVWdCeUFNU1hFRVFDQUhJQW9nQlNnQ0tDSUdJQVVvQWl3aUFIUWdDM1pCQW5ScUlnMHZBUUE3QUFBZ0J5QU5MUUFEYWlJRElBb2dCaUFBSUEwdEFBSnFJZ0IwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQUNBR0xRQUNhallDTENBRElBWXRBQU5xSVFjTUFRVWdBa0VDYXlFR0EwQWdCVUVvYWhBUElRTWdCU2dDS0NFTUlBVW9BaXdoQUNBR0lBZEpJQU55UlFSQUlBY2dDaUFNSUFCMElBdDJRUUowYWlJREx3RUFPd0FBSUFVZ0FDQURMUUFDYWpZQ0xDQUhJQU10QUFOcUlRY01BUXNMQTBBZ0JpQUhTVVVFUUNBSElBb2dEQ0FBZENBTGRrRUNkR29pQXk4QkFEc0FBQ0FISUFNdEFBTnFJUWNnQUNBRExRQUNhaUVBREFFTEN3SkFJQUlnQjAwTkFDQUhJQW9nRENBQWRDQUxkaUlDUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUFJQU10QUFKcUlRQU1BUXNnQUVFZlN3MEFRU0FnQUNBS0lBSkJBblJxTFFBQ2FpSUFJQUJCSUU4YklRQUxJQmxCQTJzaERBTkFJQVZCRkdvUUQwVWdDQ0FNU1hFRVFDQUlJQW9nQlNnQ0ZDSUdJQVVvQWhnaUFuUWdDM1pCQW5ScUlnMHZBUUE3QUFBZ0NDQU5MUUFEYWlJRElBb2dCaUFDSUEwdEFBSnFJZ0owSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQWlBR0xRQUNhallDR0NBRElBWXRBQU5xSVFnTUFRVWdHVUVDYXlFREEwQWdCVUVVYWhBUElRSWdCU2dDRkNFR0lBVW9BaGdoQnlBRElBaEpJQUp5UlFSQUlBZ2dDaUFHSUFkMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFVZ0J5QUNMUUFDYWpZQ0dDQUlJQUl0QUFOcUlRZ01BUXNMQTBBZ0F5QUlTVVVFUUNBSUlBb2dCaUFIZENBTGRrRUNkR29pQWk4QkFEc0FBQ0FJSUFJdEFBTnFJUWdnQnlBQ0xRQUNhaUVIREFFTEN3SkFJQWdnR1U4TkFDQUlJQW9nQmlBSGRDQUxkaUlDUVFKMGFpSURMUUFBT2dBQUlBTXRBQU5CQVVZRVFDQUhJQU10QUFKcUlRY01BUXNnQjBFZlN3MEFRU0FnQnlBS0lBSkJBblJxTFFBQ2FpSUNJQUpCSUU4YklRY0xBMEFnQlJBUFJTQUVJQ0JKY1FSQUlBUWdDaUFGS0FJQUlnWWdCU2dDQkNJQ2RDQUxka0VDZEdvaURDOEJBRHNBQUNBRUlBd3RBQU5xSWdNZ0NpQUdJQUlnREMwQUFtb2lBblFnQzNaQkFuUnFJZ1F2QVFBN0FBQWdCU0FDSUFRdEFBSnFOZ0lFSUFNZ0JDMEFBMm9oQkF3QkJTQWZRUUpySVFNRFFDQUZFQThoQWlBRktBSUFJUVlnQlNnQ0JDRUlJQU1nQkVrZ0FuSkZCRUFnQkNBS0lBWWdDSFFnQzNaQkFuUnFJZ0l2QVFBN0FBQWdCU0FJSUFJdEFBSnFOZ0lFSUFRZ0FpMEFBMm9oQkF3QkN3c0RRQ0FESUFSSlJRUkFJQVFnQ2lBR0lBaDBJQXQyUVFKMGFpSUNMd0VBT3dBQUlBUWdBaTBBQTJvaEJDQUlJQUl0QUFKcUlRZ01BUXNMQWtBZ0JDQWZUdzBBSUFRZ0NpQUdJQWgwSUF0MklnSkJBblJxSWdNdEFBQTZBQUFnQXkwQUEwRUJSZ1JBSUFnZ0F5MEFBbW9oQ0F3QkN5QUlRUjlMRFFCQklDQUlJQW9nQWtFQ2RHb3RBQUpxSWdJZ0FrRWdUeHNoQ0F0QmJFRnNRV3hCYkVGc1FXeEJiRUZzSUFFZ0NFRWdSeHNnQlNnQ0NDQUZLQUlNUnhzZ0IwRWdSeHNnQlNnQ0hDQUZLQUlnUnhzZ0FFRWdSeHNnQlNnQ01DQUZLQUkwUnhzZ0NVRWdSeHNnQlNnQ1JDQUZLQUpJUnhzaENRd0pDd0FMQUFzQUN3QUxBQXNBQ3dBTEFBdEJiQ0VKQ3lBRlFkQUFhaVFBSUFrTDdCQUJIbjhqQUVIUUFHc2lCU1FBUVd3aENRSkFJQU5CQ2trTkFBSkFJQU1nQWk4QUJDSUdJQUl2QUFBaUJ5QUNMd0FDSWdocWFrRUdhaUlPU1EwQUlBUXZBUUloRHlBRlFUeHFJQUpCQm1vaUFpQUhFQTBpQ1VHSWYwc05BU0FGUVNocUlBSWdCMm9pQWlBSUVBMGlDVUdJZjBzTkFTQUZRUlJxSUFJZ0NHb2lBaUFHRUEwaUNVR0lmMHNOQVNBRklBSWdCbW9nQXlBT2F4QU5JZ2xCaUg5TERRRWdCRUVFYWlFS0lBQWdBV29pSEVFRGF5RWRRUUFnRDJ0QkgzRWhDeUFGS0FJSUlSRWdCU2dDSENFU0lBVW9BakFoRXlBRktBSkVJUlFnQlNnQ0JDRUpJQVVvQWhnaEJpQUZLQUlzSVFjZ0JTZ0NRQ0VJSUFVb0FoQWhIaUFGS0FJa0lSOGdCU2dDT0NFZ0lBVW9Ba3doSVNBRktBSUFJUlVnQlNnQ0ZDRVdJQVVvQWlnaEZ5QUZLQUk4SVJoQkFTRU5JQUFnQVVFRGFrRUNkaUlDYWlJT0lBSnFJZzhnQW1vaUdTRUVJQThoQWlBT0lRTURRQ0FOUlNBRUlCMVBja1VFUUNBS0lCZ2dDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBQWdDaUFYSUFkMElBdDJRUUYwYWlJTUxRQUJJUkFnQXlBTUxRQUFPZ0FBSUFvZ0ZpQUdkQ0FMZGtFQmRHb2lEQzBBQVNFYUlBSWdEQzBBQURvQUFDQUtJQlVnQ1hRZ0MzWkJBWFJxSWd3dEFBRWhHeUFFSUF3dEFBQTZBQUFnQ2lBWUlBZ2dEV29pQ0hRZ0MzWkJBWFJxSWd3dEFBRWhEU0FBSUF3dEFBQTZBQUVnQ2lBWElBY2dFR29pQjNRZ0MzWkJBWFJxSWd3dEFBRWhFQ0FESUF3dEFBQTZBQUVnQ2lBV0lBWWdHbW9pREhRZ0MzWkJBWFJxSWdZdEFBRWhHaUFDSUFZdEFBQTZBQUVnQ2lBVklBa2dHMm9pRzNRZ0MzWkJBWFJxSWdrdEFBRWhJaUFFSUFrdEFBQTZBQUVnQ0NBTmFpRUdRUU1oQ1FKL0lCUWdJVWtFUUVFRElRMGdCZ3dCQ3lBVUlBWkJBM1pySWhRb0FBQWhHRUVBSVEwZ0JrRUhjUXNoQ0NBSElCQnFJUVlnRXlBZ1NRUi9JQVlGSUJNZ0JrRURkbXNpRXlnQUFDRVhRUUFoQ1NBR1FRZHhDeUVISUF3Z0dtb2hEQ0FKSUExeUlSQkJBeUVOQW44Z0VpQWZTUVJBSUF3aEJrRUREQUVMSUF4QkIzRWhCaUFTSUF4QkEzWnJJaElvQUFBaEZrRUFDeUFiSUNKcUlRd2dFSEloRUNBUklCNUpCSDhnREFVZ0VTQU1RUU4yYXlJUktBQUFJUlZCQUNFTklBeEJCM0VMSVFrZ0JFRUNhaUVFSUFKQkFtb2hBaUFEUVFKcUlRTWdBRUVDYWlFQUlBMGdFSEpGSVEwTUFRc0xJQVVnQnpZQ0xDQUZJQWcyQWtBZ0JTQUdOZ0lZSUFVZ0NUWUNCQ0FGSUJRMkFrUWdCU0FUTmdJd0lBVWdFallDSENBRklCRTJBZ2dnQlNBWU5nSThJQVVnRnpZQ0tDQUZJQlkyQWhRZ0JTQVZOZ0lBSUFBZ0Rrc2dBeUFQUzNJTkFFRnNJUWtnQWlBWlN3MEJJQTVCQTJzaENRTkFJQVZCUEdvUUR5QUFJQWxQY2tVRVFDQUtJQVVvQWp3aUJpQUZLQUpBSWdkMElBdDJRUUYwYWlJSUxRQUJJUXdnQUNBSUxRQUFPZ0FBSUFvZ0JpQUhJQXhxSWdaMElBdDJRUUYwYWlJSExRQUFJUWdnQlNBR0lBY3RBQUZxTmdKQUlBQWdDRG9BQVNBQVFRSnFJUUFNQVFzTEEwQWdCVUU4YWhBUElRY2dCU2dDUENFR0lBVW9Ba0FoQ1NBQUlBNVBJQWR5UlFSQUlBb2dCaUFKZENBTGRrRUJkR29pQmkwQUFDRUhJQVVnQ1NBR0xRQUJhallDUUNBQUlBYzZBQUFnQUVFQmFpRUFEQUVMQ3dOQUlBQWdEazlGQkVBZ0NpQUdJQWwwSUF0MlFRRjBhaUlITFFBQklBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0NXb2hDUXdCQ3dzZ0QwRURheUVBQTBBZ0JVRW9haEFQSUFBZ0EwMXlSUVJBSUFvZ0JTZ0NLQ0lHSUFVb0Fpd2lCM1FnQzNaQkFYUnFJZ2d0QUFFaERpQURJQWd0QUFBNkFBQWdDaUFHSUFjZ0Rtb2lCblFnQzNaQkFYUnFJZ2N0QUFBaENDQUZJQVlnQnkwQUFXbzJBaXdnQXlBSU9nQUJJQU5CQW1vaEF3d0JDd3NEUUNBRlFTaHFFQThoQnlBRktBSW9JUVlnQlNnQ0xDRUFJQU1nRDA4Z0IzSkZCRUFnQ2lBR0lBQjBJQXQyUVFGMGFpSUdMUUFBSVFjZ0JTQUFJQVl0QUFGcU5nSXNJQU1nQnpvQUFDQURRUUZxSVFNTUFRc0xBMEFnQXlBUFQwVUVRQ0FLSUFZZ0FIUWdDM1pCQVhScUlnY3RBQUVoQ0NBRElBY3RBQUE2QUFBZ0EwRUJhaUVESUFBZ0NHb2hBQXdCQ3dzZ0dVRURheUVEQTBBZ0JVRVVhaEFQSUFJZ0EwOXlSUVJBSUFvZ0JTZ0NGQ0lHSUFVb0FoZ2lCM1FnQzNaQkFYUnFJZ2d0QUFFaERpQUNJQWd0QUFBNkFBQWdDaUFHSUFjZ0Rtb2lCblFnQzNaQkFYUnFJZ2N0QUFBaENDQUZJQVlnQnkwQUFXbzJBaGdnQWlBSU9nQUJJQUpCQW1vaEFnd0JDd3NEUUNBRlFSUnFFQThoQnlBRktBSVVJUVlnQlNnQ0dDRURJQUlnR1U4Z0IzSkZCRUFnQ2lBR0lBTjBJQXQyUVFGMGFpSUdMUUFBSVFjZ0JTQURJQVl0QUFGcU5nSVlJQUlnQnpvQUFDQUNRUUZxSVFJTUFRc0xBMEFnQWlBWlQwVUVRQ0FLSUFZZ0EzUWdDM1pCQVhScUlnY3RBQUVoQ0NBQ0lBY3RBQUE2QUFBZ0FrRUJhaUVDSUFNZ0NHb2hBd3dCQ3dzRFFDQUZFQThnQkNBZFQzSkZCRUFnQ2lBRktBSUFJZ0lnQlNnQ0JDSUdkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUtJQUlnQmlBSWFpSUNkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdBaUFHTFFBQmFqWUNCQ0FFSUFjNkFBRWdCRUVDYWlFRURBRUxDd05BSUFVUUR5RUhJQVVvQWdBaEJpQUZLQUlFSVFJZ0JDQWNUeUFIY2tVRVFDQUtJQVlnQW5RZ0MzWkJBWFJxSWdZdEFBQWhCeUFGSUFJZ0JpMEFBV28yQWdRZ0JDQUhPZ0FBSUFSQkFXb2hCQXdCQ3dzRFFDQUVJQnhQUlFSQUlBb2dCaUFDZENBTGRrRUJkR29pQnkwQUFTRUlJQVFnQnkwQUFEb0FBQ0FFUVFGcUlRUWdBaUFJYWlFQ0RBRUxDMEZzUVd4QmJFRnNRV3hCYkVGc1FXd2dBU0FDUVNCSEd5QUZLQUlJSUFVb0FneEhHeUFEUVNCSEd5QUZLQUljSUFVb0FpQkhHeUFBUVNCSEd5QUZLQUl3SUFVb0FqUkhHeUFKUVNCSEd5QUZLQUpFSUFVb0FraEhHeUVKREFFTFFXd2hDUXNnQlVIUUFHb2tBQ0FKQzFnQkEzOENRQ0FBS0FLUTZ3RWlBVVVOQUNBQktBSUFJQUZCdE5VQmFpZ0NBQ0lDSUFGQnVOVUJhaWdDQUNJREVCTWdBZ1JBSUFNZ0FTQUNFUUlBREFFTElBRVFCZ3NnQUVFQU5nS2c2d0VnQUVJQU53T1E2d0VMNlFNQ0JIOENmaUFBUVFCQktCQURJUVFnQWtFQlFRVWdBeHNpQUVrRVFDQUFEd3NnQVVVRVFFRi9Ed3RCQVNFR0FrQUNRQ0FEUVFGR0RRQWdBeUVHSUFFb0FBQWlCVUdvNnI1cFJnMEFRWFloQXlBRlFYQnhRZERVdE1JQlJ3MEJRUWdoQXlBQ1FRaEpEUUVnQVRVQUJDRUlJQVJCQVRZQ0ZDQUVJQWczQXdCQkFBOExJQUVnQWlBR0VCb2lBeUFDU3cwQUlBUWdBellDR0VGeUlRTWdBQ0FCYWlJRlFRRnJMUUFBSWdKQkNIRU5BQ0FDUVNCeElnWkZCRUJCY0NFRElBVXRBQUFpQlVHbkFVc05BU0FGUVFkeHJVSUJJQVZCQTNaQkNtcXRoaUlJUWdPSWZpQUlmQ0VKSUFCQkFXb2hBQXNnQWtFR2RpRUZJQUpCQW5aQkFDRURBa0FDUUFKQUFrQWdBa0VEY1VFQmF3NERBQUVDQXdzZ0FDQUJhaTBBQUNFRElBQkJBV29oQUF3Q0N5QUFJQUZxTHdBQUlRTWdBRUVDYWlFQURBRUxJQUFnQVdvb0FBQWhBeUFBUVFScUlRQUxRUUZ4SVFJQ2ZnSkFBa0FDUUFKQUlBVkJBV3NPQXdFQ0F3QUxRbjhnQmtVTkF4b2dBQ0FCYWpFQUFBd0RDeUFBSUFGcU13QUFRb0FDZkF3Q0N5QUFJQUZxTlFBQURBRUxJQUFnQVdvcEFBQUxJUWdnQkNBQ05nSWdJQVFnQXpZQ0hDQUVJQWczQXdCQkFDRURJQVJCQURZQ0ZDQUVJQWdnQ1NBR0d5SUlOd01JSUFSQ2dJQUlJQWdnQ0VLQWdBaGFHejRDRUFzZ0F3dGZBUUYvUWJoL0lRTWdBVUVCUVFVZ0Foc2lBazhFZnlBQUlBSnFRUUZyTFFBQUlnQkJBM0ZCQW5SQm9CNXFLQUlBSUFKcUlBQkJCSFpCREhGQnNCNXFLQUlBYWlBQVFTQnhJZ0ZGYWlBQlFRVjJJQUJCd0FCSmNXb0ZRYmgvQ3dzTUFDQUFJQUVnQWtFQUVCa0xsd01DQlg4Q2ZpTUFRVUJxSWdRa0FBSkFBMEFnQVVFRlR3UkFBa0FnQUNnQUFFRndjVUhRMUxUQ0FVWUVRRUorSVFjZ0FVRUlTUTBFSUFBb0FBUWlBa0YzU3cwRUlBSkJDR29pQXlBQlN3MEVJQUpCZ1g5SkRRRU1CQXNnQkVFWWFpQUFJQUVRR3lFQ1FuNGdCQ2tER0VJQUlBUW9BaXhCQVVjYklBSWJJZ2RDZlZZTkF5QUhJQWg4SWdnZ0IxUkNmaUVIRFFNQ1FBSkFJQUZCQ0VrTkFDQUFLQUFBUVhCeFFkRFV0TUlCUncwQUlBQW9BQVFpQWtGM1N3MEZRYmgvSUFKQkNHb2lBaUFCSUFKSkd5RUREQUVMSUFSQkdHb2dBQ0FCRUJzaUFrR0lmMHNFUUNBQ0lRTU1BUXRCdUg4aEF5QUNEUUFnQVNBRUtBSXdJZ0pySVFVZ0FDQUNhaUVHQTBBZ0JpQUZJQVJCREdvUUhTSURRWWgvU3cwQklBTkJBMm9pQWlBRlN3UkFRYmgvSVFNTUFnc2dCU0FDYXlFRklBSWdCbW9oQmlBRUtBSVFSUTBBQ3lBRUtBSTRCSDlCdUg4aEF5QUZRUVJKRFFFZ0JrRUVhZ1VnQmdzZ0FHc2hBd3NnQTBHSWYwc05Bd3NnQVNBRGF5RUJJQUFnQTJvaEFBd0JDd3RDZmlBSUlBRWJJUWNMSUFSQlFHc2tBQ0FIQzJRQkFYOUJ1SDhoQXdKQUlBRkJBMGtOQUNBQUxRQUNJUUVnQWlBQUx3QUFJZ0JCQVhFMkFnUWdBaUFBUVFGMlFRTnhJZ00yQWdBZ0FpQUFJQUZCRUhSeVFRTjJJZ0EyQWdnQ1FBSkFJQU5CQVdzT0F3SUJBQUVMUVd3UEN5QUFJUU1MSUFNTFJBRUNmeUFCSUFJb0FnUWlBeUFCS0FJRWFpSUVOZ0lFSUFBZ0EwRUNkRUdnSFdvb0FnQWdBU2dDQUVFQUlBUnJkbkUyQWdBZ0FSQVBHaUFBSUFKQkNHbzJBZ1FMemdFQkJuOUJ1bjhoQ2dKQUlBSW9BZ1FpQ0NBQ0tBSUFJZ2xxSWcwZ0FTQUFhMHNOQUVGc0lRb2dDU0FFSUFNb0FnQWlDMnRMRFFBZ0FDQUphaUlFSUFJb0FnZ2lER3NoQWlBQUlBRkJJR3NpQUNBTElBbEJBQkFnSUFNZ0NTQUxhallDQUFKQUFrQWdCQ0FGYXlBTVR3UkFJQUloQlF3QkN5QU1JQVFnQm10TERRSWdCeUFISUFJZ0JXc2lBbW9pQVNBSWFrOEVRQ0FFSUFFZ0NCQUtHZ3dDQ3lBQ0lBaHFJUWdnQkNBQlFRQWdBbXNRQ2lBQ2F5RUVDeUFFSUFBZ0JTQUlRUUVRSUFzZ0RTRUtDeUFLQzhjRUFRSi9JQUFnQTJvaEJnSkFJQU5CQjB3RVFBTkFJQUFnQms4TkFpQUFJQUl0QUFBNkFBQWdBRUVCYWlFQUlBSkJBV29oQWd3QUN3QUxJQVJCQVVZRVFBSkFJQUFnQW1zaUJVRUhUUVJBSUFBZ0FpMEFBRG9BQUNBQUlBSXRBQUU2QUFFZ0FDQUNMUUFDT2dBQ0lBQWdBaTBBQXpvQUF5QUFJQUlnQlVFQ2RDSUZRY0FlYWlnQ0FHb2lBaWdBQURZQUJDQUNJQVZCNEI1cUtBSUFheUVDREFFTElBQWdBaWtBQURjQUFBc2dBa0VJYWlFQ0lBQkJDR29oQUFzZ0FTQUdUd1JBSUFBZ0Eyb2hBU0FFUVFGSElBQWdBbXRCRDBweVJRUkFBMEFnQUNBQ0tRQUFOd0FBSUFKQkNHb2hBaUFBUVFocUlnQWdBVWtOQUF3REN3QUxJQUFnQWlrQUFEY0FBQ0FBSUFJcEFBZzNBQWdnQTBFUlNRMEJJQUJCRUdvaEFBTkFJQUFnQWlrQUVEY0FBQ0FBSUFJcEFCZzNBQWdnQUNBQ0tRQWdOd0FRSUFBZ0Fpa0FLRGNBR0NBQ1FTQnFJUUlnQUVFZ2FpSUFJQUZKRFFBTERBRUxBa0FnQUNBQlN3UkFJQUFoQVF3QkN5QUJJQUJySVFVQ1FDQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUlBSWhBd05BSUFBZ0F5a0FBRGNBQUNBRFFRaHFJUU1nQUVFSWFpSUFJQUZKRFFBTERBRUxJQUFnQWlrQUFEY0FBQ0FBSUFJcEFBZzNBQWdnQlVFUlNBMEFJQUJCRUdvaEFDQUNJUU1EUUNBQUlBTXBBQkEzQUFBZ0FDQURLUUFZTndBSUlBQWdBeWtBSURjQUVDQUFJQU1wQUNnM0FCZ2dBMEVnYWlFRElBQkJJR29pQUNBQlNRMEFDd3NnQWlBRmFpRUNDd05BSUFFZ0JrOE5BU0FCSUFJdEFBQTZBQUFnQVVFQmFpRUJJQUpCQVdvaEFnd0FDd0FMQzY0SEFnVi9BWDRqQUVHQUFXc2lFU1FBSUJFZ0F6WUNmRUYvSVE4Q1FBSkFBa0FDUUFKQUlBSU9CQUVBQXdJRUN5QUdSUVJBUWJoL0lROE1CQXRCYkNFUElBVXRBQUFpQWlBRFN3MERJQWdnQWtFQ2RDSUNhaWdDQUNFRElBSWdCMm9vQWdBaEFpQUFRUUE2QUFzZ0FFSUFOd0lBSUFBZ0FqWUNEQ0FBSUFNNkFBb2dBRUVBT3dFSUlBRWdBRFlDQUVFQklROE1Bd3NnQVNBSk5nSUFRUUFoRHd3Q0N5QUtSUVJBUVd3aER3d0NDMEVBSVE4Z0MwVWdERUVaU0hJTkFVRUlJQVIwUVFocUlRQkJBQ0VEQTBBZ0FDQURUUTBDSUFOQlFHc2hBd3dBQ3dBTFFXd2hEeUFSSUJGQi9BQnFJQkZCK0FCcUlBVWdCaEFNSWdOQmlIOUxEUUFnRVNnQ2VDSUNJQVJMRFFBZ0VTZ0NmRUVCYWlFSklBQkJDR29oQzBHQWdBSWdBblJCRUhVaEJVRUJJUkJCQVNBQ2RDSVBRUUZySWdvaEVnTkFJQWtnRGtjRVFBSkFJQkVnRGtFQmRDSUVhaThCQUNJTVFmLy9BMFlFUUNBTElCSkJBM1JxSUE0MkFnUWdFa0VCYXlFU1FRRWhEQXdCQ3lBUVFRQWdCU0FNd1VvYklSQUxJQVFnRFdvZ0REc0JBQ0FPUVFGcUlRNE1BUXNMSUFBZ0FqWUNCQ0FBSUJBMkFnQUNRQ0FLSUJKR0JFQWdEVUhxQUdvaEJrRUFJUkJCQUNFTUEwQWdDU0FRUmdSQUlBOUJBM1lnRDBFQmRtcEJBMm9pQlVFQmRDRUVRUUFoREVFQUlSSURRRUVBSVE0Z0R5QVNUUTBFQTBBZ0RrRUNSd1JBSUFzZ0JTQU9iQ0FNYWlBS2NVRURkR29nQmlBT0lCSnFhaTBBQURZQ0JDQU9RUUZxSVE0TUFRc0xJQkpCQW1vaEVpQUVJQXhxSUFweElRd01BQXNBQlNBUklCQkJBWFJxTGdFQUlRVWdCaUFNYWlJRUlCTTNBQUJCQ0NFT0EwQWdCU0FPU2dSQUlBUWdEbW9nRXpjQUFDQU9RUWhxSVE0TUFRc0xJQk5DZ1lLRWlKQ2d3SUFCZkNFVElCQkJBV29oRUNBRklBeHFJUXdNQVFzQUN3QUxJQTlCQTNZZ0QwRUJkbXBCQTJvaEJVRUFJUkJCQUNFT0EwQWdDU0FRUmcwQlFRQWhEQ0FSSUJCQkFYUnFMZ0VBSWdSQkFDQUVRUUJLR3lFRUEwQWdCQ0FNUndSQUlBc2dEa0VEZEdvZ0VEWUNCQU5BSUFVZ0Rtb2dDbkVpRGlBU1N3MEFDeUFNUVFGcUlRd01BUXNMSUJCQkFXb2hFQXdBQ3dBTElBSkJBV29oQlVFQUlRd0RRQ0FNSUE5SEJFQWdEU0FMSUF4QkEzUnFJZ2tvQWdRaUJFRUJkR29pQWlBQ0x3RUFJZ1pCQVdvN0FRQWdDU0FGSUFablFXQnphaUlDT2dBRElBa2dCaUFDZENBUGF6c0JBQ0FKSUFnZ0JFRUNkQ0lDYWlnQ0FEb0FBaUFKSUFJZ0Iyb29BZ0EyQWdRZ0RFRUJhaUVNREFFTEN5QUJJQUEyQWdBZ0F5RVBDeUFSUVlBQmFpUUFJQThMN1ZvQ08zOEdmaU1BUWVBQmF5SUVKQUFDUUVHdzdBa1FCU0lGUlFSQVFVQWhCd3dCQ3lBRlFnQTNBdlRxQVNBRlFRQTJBc1RyQVNBRlFRQTJBclRyQVNBRlFnQTNBcHpyQVNBRlFRQTJBcmpwQVNBRlFRQTJBcXpzQ1NBRlFnQTNBdFRyQVNBRlFnQTNBcXpyQVNBRlFnQTNBNGpyQVNBRlFnQTNBdVRxQVNBRlFnQTNBdVRyQVNBRlFZR0FnTUFBTmdLODZ3RWdCVUlBTndLazZ3RWdCVUg4NmdGcVFRQTJBZ0FnQlVHUTZ3RnFRZ0EzQXdBZ0JSQVlJQVZCck5VQmFpRVVJQVZCK09zQmFpRWNJQVZCc09vQmFpRWlJQVZCb0RCcUlTb2dCVUdZSUdvaEt5QUZRYWpRQUdvaEhpQUZRUkJxSVN3Z0JVRUlhaUVvSUFWQkJHb2hMU0FGUWNEcEFXb2hLU0FGUVlqckFXb2dCRUdVQVdvaEx5QUVRWXdCYWlFd0lBUkJoQUZxSVRFZ0JFSGNBR29oTWlBRVFkUUFhaUV6SUFSQnpBQnFJVFFnQUNFZEFrQUNRQUpBQWtBQ1FBTkFRUUZCQlNBRktBTGs2Z0ViSVFZQ1FBTkFJQU1nQmtrTkFTQUNLQUFBUVhCeFFkRFV0TUlCUmdSQVFiaC9JUWNnQTBFSVNRMElJQUlvQUFRaURrRjNTd1JBUVhJaEJ3d0pDeUFESUE1QkNHb2lDVWtOQ0NBT1FZQi9Td1JBSUFraEJ3d0pDeUFESUFscklRTWdBaUFKYWlFQ0RBRUxDeUFGUWdBM0FxenBBU0FGUWdBM0EranBBU0FGUVFBMkFwanJBU0FGUWdBM0E0RHFBU0FGUWdNM0EvanBBU0FGUWJUcEFXcENBRGNDQUNBRlFmRHBBV3BDQURjREFDQUZRYWpRQUdvaUNVR01nSURnQURZQ0FDQUZRYXpRQVdwQjRCSXBBZ0EzQWdBZ0JVRzAwQUZxUWVnU0tBSUFOZ0lBSUFVZ0JVRVFhallDQUNBRklBVkJvREJxTmdJRUlBVWdCVUdZSUdvMkFnZ2dCU0FKTmdJTUlBVkJBVUVGSUFVb0F1VHFBUnMyQXJ6cEFRSkFJQUZGRFFBZ0JTZ0NyT2tCSWdrZ0hVWU5BQ0FGSUFrMkFyanBBU0FGSUIwMkFxenBBU0FGS0FLdzZRRWhEaUFGSUIwMkFyRHBBU0FGSUIwZ0RpQUphMm8yQXJUcEFRdEJ1SDhoQ1NBRFFRVkJDU0FGS0FMazZnRWlCaHRKRFFVZ0FrRUJRUVVnQmhzZ0JoQWFJZzVCaUg5TEJFQWdEaUVKREFVTElBTWdEa0VEYWtrTkJTQXBJQUlnRGlBR0VCa2lCa0dJZjBzRVFDQUdJUWtNQlFzZ0JnMEZBa0FDUUNBRktBS282d0ZCQVVjTkFDQUZLQUtrNndFaUNVVU5BQ0FGS0FLVTZ3RkZEUUFnQ1NnQ0JFRUJheUlISUFVb0F0enBBU0lLclVLSGxhK3ZtTGJlbTU1L2ZrTEp6OW15OGVXNjZpZUZRaGVKUXMvVzA3N1N4NnZaUW41QytmUGQ4Wm4ybWFzV2ZDSS9RaUdJSUQrRlFzL1cwNzdTeDZ2WlFuNGlQMElkaUNBL2hVTDU4OTN4bWZhWnF4WitJajlDSUlnZ1A0V25jU0VHSUFrb0FnQWhGUU5BUVFBaENBSkFJQlVnQmtFQ2RHb29BZ0FpQ1VVTkFDQUpLQUlJUVFoSkRRQWdDU2dDQkNJU0tBQUFRYmZJd3VGK1J3MEFJQklvQUFRaENBc2dDQ0FLUndSQUlBWWdCM0ZCQVdvaEJpQUlEUUVMQ3lBSlJRMEFJQVVRR0NBRlFYODJBcURyQVNBRklBazJBcFRyQVNBRklBVW9BdHpwQVNJSU5nS1k2d0VNQVFzZ0JTZ0MzT2tCSVFnTEFrQWdDRVVOQUNBRktBS1k2d0VnQ0VZTkFFRmdJUWtNQmdzQ1FDQUZLQUxnNlFFRVFDQUZJQVVvQXVqcUFTSUpSVFlDN09vQklBa05BU0FGUXZucTBORG55YUhrNFFBM0E2anFBU0FGUWdBM0E2RHFBU0FGUXMvVzA3N1N4NnZaUWpjRG1Pb0JJQVZDMXV1Qzd1cjlpZlhnQURjRGtPb0JJQVZDQURjRGlPb0JJQ0pCQUVFb0VBTWFEQUVMSUFWQkFEWUM3T29CQ3lBQklCMXFJU1VnQlNBRktRUG82UUVnRHExOE53UG82UUVnQXlBT2F5RURJQUlnRG1vaEFpQWRJUTREUUNBQ0lBTWdCRUVzYWhBZEloVkJpSDlMQkVBZ0ZTRUpEQVlMSUFOQkEyc2lOU0FWU1EwRUlBSkJBMm9oRzBGc0lRa0NRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUNBRUtBSXNEZ01DQVFBVkN5QVZRZi8vQjBzTkV5QVZRUU5KRFJJZ0JTa0R5T2tCSVQ4Q1FBSkFJQnN0QUFBaUNVRURjU0lhUVFGckRnTUdBUUFIQ3lBRktBS0E2Z0VOQUVGaUlRa01GUXNnRlVFRlNRMFNJQnNvQUFBaEF3Si9Ba0FDUUFKQUlBbEJBblpCQTNFaUNVRUNhdzRDQVFJQUN5QUpRUUJISVFjZ0EwRUVka0gvQjNFaEMwRURJUVlnQTBFT2RrSC9CM0VNQWd0QkJDRUdJQU5CQkhaQi8vOEFjU0VMUVFFaEJ5QURRUkoyREFFTElBTkJCSFpCLy84UGNTSUxRWUNBQ0VzTkUwRUJJUWRCQlNFR0lBSXRBQWRCQ25RZ0EwRVdkbklMSWdnZ0Jtb2lDU0FWU3cwU0FrQWdDMEdCQmtrTkFDQUZLQUtjNndGRkRRQkJBQ0VEQTBBZ0EwR0RnQUZMRFFFZ0EwRkFheUVEREFBTEFBc2dCaUFiYWlFUElCcEJBMGNOQmlBRktBSU1JZ0l0QUFGQkNIUWhBeUFIRFFjZ0EwVU5DQ0FFUWZBQWFpQVBJQWdRRFNJRFFZaC9TdzBKSUFKQkJHb2hCaUFMSUJ4cUloSkJBMnNoQ2tFQUlBSXZBUUpyUVI5eElRY2dIQ0VEQTBBZ0JFSHdBR29RRDBVZ0F5QUtTWEVFUUNBRElBWWdCQ2dDY0NJSUlBUW9BblFpRDNRZ0IzWkJBblJxSWdJdkFRQTdBQUFnQXlBQ0xRQURhaUlESUFZZ0NDQVBJQUl0QUFKcUlnaDBJQWQyUVFKMGFpSUNMd0VBT3dBQUlBUWdDQ0FDTFFBQ2FqWUNkQ0FESUFJdEFBTnFJUU1NQVFVZ0VrRUNheUVJQTBBZ0JFSHdBR29RRHlFUElBUW9BbkFoQ2lBRUtBSjBJUUlnQXlBSVN5QVBja1VFUUNBRElBWWdDaUFDZENBSGRrRUNkR29pQ2k4QkFEc0FBQ0FFSUFJZ0NpMEFBbW8yQW5RZ0F5QUtMUUFEYWlFRERBRUxDd05BSUFNZ0NFMEVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lEeThCQURzQUFDQURJQTh0QUFOcUlRTWdBaUFQTFFBQ2FpRUNEQUVMQ3dKQUlBTWdFazhOQUNBRElBWWdDaUFDZENBSGRrRUNkR29pQXkwQUFEb0FBQ0FETFFBRFFRRkdCRUFnQWlBRExRQUNhaUVDREFFTElBSkJIMHNOQUVFZ0lBSWdBeTBBQW1vaUFpQUNRU0JQR3lFQ0MwRnNRV3dnQ3lBRUtBSjRJQVFvQW54SEd5QUNRU0JIR3lFRERBc0xBQXNBQ3lBRUtBSTBJZ0lnSlNBT2Ewc05DaUFPUlFSQVFRQWhDU0FDRFFJTURnc2dEaUFiTFFBQUlBSVFBeG9nQWlFSkRBd0xJQlVnSlNBT2Ewc05DU0FPRFFGQkFDRUpJQlZGRFF3TFFiWi9JUWtNRVFzZ0RpQWJJQlVRQWhvZ0ZTRUpEQW9MSUJ3Z0d3Si9Ba0FDUUFKQUlBbEJBblpCQTNGQkFXc09Bd0VBQWdBTElBbEJBM1loQTBFQkRBSUxJQnN2QUFCQkJIWWhBMEVDREFFTElCVkJCRWtORGlBQ0x3QURJQUl0QUFWQkVIUnlJZ0pCajRDQUFVc05EaUFDUVFSMklRTkJBd3NpQW1vdEFBQWdBMEVnYWhBRElRa2dCU0FETmdLQTZ3RWdCU0FKTmdMdzZnRWdBa0VCYWlFSkRBVUxJQlVDZndKQUFrQUNRQ0FKUVFKMlFRTnhRUUZyRGdNQkFBSUFDeUFKUVFOMklRTkJBUXdDQ3lBYkx3QUFRUVIySVFOQkFnd0JDeUFDTHdBRElBSXRBQVZCRUhSeVFRUjJJUU5CQXdzaUFpQURhaUlKUVNCcVNRUkFJQWtnRlVzTkRTQWNJQUlnRzJvZ0F4QUNJUUlnQlNBRE5nS0E2d0VnQlNBQ05nTHc2Z0VnQWlBRGFpSUNRZ0EzQUJnZ0FrSUFOd0FRSUFKQ0FEY0FDQ0FDUWdBM0FBQU1CUXNnQlNBRE5nS0E2d0VnQlNBQ0lCdHFOZ0x3NmdFTUJBc2dCMFVFUUNBZUlBOGdDQ0FVRUJRaUFrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGU0VEREFNTElBdEZJQWhGY2cwTElBdEJDSFlpQXlBSUlBdEpCSDhnQ0VFRWRDQUxiZ1ZCRHd0QkdHd2lBa0dNQ0dvb0FnQnNJQUpCaUFocUtBSUFhaUlHUVFOMklBWnFJQUpCZ0FocUtBSUFJQUpCaEFocUtBSUFJQU5zYWtrRVFDTUFRUkJySWhBa0FDQWVLQUlBSVFNZ0ZFSHdCR3BCQUVIc0FCQURJUVpCVkNFQ0FrQWdBMEgvQVhFaURFRU1TdzBBQWtBZ0ZFSGNDV29nQmlBUVFRaHFJQkJCREdvZ0R5QUlJQlJCM0F0cUloY1FDeUlTUVloL1N3MEFJQkFvQWd3aUJpQU1TdzBCSUJSQnFBVnFJUTBnRkVHa0JXb2hOaUFlUVFScUlSRWdBMEdBZ0lCNGNTRTNJQVpCQVdvaUV5RUNJQVloQXdOQUlBSWlCMEVCYXlFQ0lBTWlDa0VCYXlFRElCUWdDa0VDZEdvb0F2QUVSUTBBQzBFQklBY2dCMEVCVFJzaEZrRUFJUWRCQVNFQ0EwQWdBaUFXUndSQUlCUWdBa0VDZENJRGFpZ0M4QVFoR0NBRElBMXFJQWMyQWdBZ0FrRUJhaUVDSUFjZ0dHb2hCd3dCQ3dzZ0RTQUhOZ0lBUVFBaEFpQVFLQUlJSVFNRFFDQUNJQU5IQkVBZ0RTQUNJQlJxUWR3SmFpMEFBQ0lZUVFKMGFpSVpJQmtvQWdBaUdVRUJhallDQUNBVUlCbEJBWFJxSWhrZ0dEb0EzUVVnR1NBQ09nRGNCU0FDUVFGcUlRSU1BUXNMUVFBaEF5QU5RUUEyQWdBZ0RDQUdRWDl6YWlFR1FRRWhBZ05BSUFJZ0ZrY0VRQ0FVSUFKQkFuUnFJZzBnQXpZQ0FDQU5LQUx3QkNBQ0lBWnFkQ0FEYWlFRElBSkJBV29oQWd3QkN3c2dEQ0FUSUFwcklnWnJRUUZxSVFvZ0JpRURBMEFnQXlBS1NRUkFJQlFnQTBFMGJHb2hEVUVCSVFJRFFDQUNJQlpIQkVBZ0RTQUNRUUowSWhocUlCUWdHR29vQWdBZ0EzWTJBZ0FnQWtFQmFpRUNEQUVMQ3lBRFFRRnFJUU1NQVFzTElCY2dGRUUwRUFJaE9DQVVRWkFNYWlFNUlCTWdER3NoT2lBVVFkd0ZhaUVYUVFBaENnTkFBa0FDUUNBSElBcEhCRUJCQVNBTUlCTWdGeUFLUVFGMGFpSUNMUUFCSWcxcklnTnJJaGgwSVJrZ0FpMEFBQ0VXSURnZ0RVRUNkR29pSHlnQ0FDRUNJQVlnR0UwRVFDQTJRUUVnQXlBNmFpSU5JQTFCQVV3YklpQkJBblFpSkdvb0FnQWhEU0E1SUJRZ0EwRTBiR3BCTkJBQ0lTRWdEVUVCZENFbUlCRWdBa0VDZEdvaEl5QWdRUUZORFFJZ0EwRVFkRUdBZ1B3SGNTQVdja0dBZ0lBSWNpRWdJQ0VnSkdvb0FnQWhKRUVBSVFJRFFDQUNJQ1JHRFFNZ0l5QUNRUUowYWlBZ05nRUFJQUpCQVdvaEFnd0FDd0FMSUFJZ0FpQVphaUlOSUFJZ0RVc2JJUTBnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFREEwQWdBaUFOUmcwRElCRWdBa0VDZEdvZ0F6WUJBQ0FDUVFGcUlRSU1BQXNBQ3lBZUlBeEJFSFFnTjNJZ0RISkJnQUp5TmdJQURBTUxJQWNnRFdzaEpDQVhJQ1pxSVNaQkFDRU5BMEFnRFNBa1JnMEJRUUVnR0NBVElDWWdEVUVCZEdvaUp5MEFBU0lDYXlJN2EzUWlQQ0FoSUFKQkFuUnFJaUFvQWdBaUFtb2hQU0FESUR0cVFSQjBRWUNBL0FkeElDY3RBQUJCQ0hSeUlCWnlRWUNBZ0JCeUlTY0RRQ0FqSUFKQkFuUnFJQ2MyQVFBZ0FrRUJhaUlDSUQxSkRRQUxJQ0FnSUNnQ0FDQThhallDQUNBTlFRRnFJUTBNQUFzQUN5QWZJQjhvQWdBZ0dXbzJBZ0FnQ2tFQmFpRUtEQUFMQUFzZ0VpRUNDeUFRUVJCcUpBQWdBa0dJZjBzZ0FpQUlUM0lORENBY0lBc2dBaUFQYWlBSUlBSnJJQjRRRmlFRERBTUxJQjRnRHlBSUlCUVFGQ0lDUVloL1N5QUNJQWhQY2cwTElCd2dDeUFDSUE5cUlBZ2dBbXNnSGhBWElRTU1BZ3NnQXdSQUlCd2dDeUFQSUFnZ0FoQVdJUU1NQWdzZ0hDQUxJQThnQ0NBQ0VCY2hBd3dCQ3lBY0lBc2dEeUFJSUFJUUZTRURDeUFEUVloL1N3MElJQVVnQ3pZQ2dPc0JJQVVnSERZQzhPb0JJQVZCQVRZQ2dPb0JJQnBCQWtZRVFDQUZJQjQyQWd3TElBc2dIR29pQWtJQU53QUFJQUpDQURjQUdDQUNRZ0EzQUJBZ0FrSUFOd0FJSUFsQmlIOUxEUW9MSUFrZ0ZVWU5DQ0FWSUFscklRWWdCU2dDbk9zQklRb0NRQ0FKSUJ0cUlnTXRBQUFpRDBVRVFFRUJJUUpCQUNFUFFiaC9JUWtnQmtFQlJnMEJEQXNMQW44Z0EwRUJhaUFQd0NJQ1FRQk9EUUFhSUFKQmYwWUVRQ0FHUVFOSURRc2dBeThBQVVHQS9nRnFJUThnQTBFRGFnd0JDeUFHUVFKSURRb2dBeTBBQVNBUFFRaDBja0dBZ0FKcklROGdBMEVDYWdzaEVrRzRmeUVKSUJKQkFXb2lBaUFWSUJ0cUlnZExEUW9nTENBRklCSXRBQUFpRWtFR2RrRWpRUWtnQWlBSElBSnJRY0FRUWRBUlFmQVNJQVVvQW9UcUFTQUtJQThnRkJBaElnbEJpSDlMRFFnZ0t5QW9JQkpCQkhaQkEzRkJIMEVJSUFJZ0NXb2lBaUFISUFKclFZQUxRWUFNUVlBWElBVW9Bb1RxQVNBRktBS2M2d0VnRHlBVUVDRWlDRUdJZjBzTkNFRnNJUWtnS2lBdElCSkJBblpCQTNGQk5FRUpJQUlnQ0dvaUFpQUhJQUpyUVlBTlFlQU9RWkFaSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUIwR0lmMHNOQ2lBQ0lBZHFJQU5ySWdJaENTQUNRWWgvU3cwS0N5QU9JQTlCQUV4eURRRUxRYnAvSVFrTUNBc2dKU0FPYXlFSklBWWdBbXNoQmlBQ0lBTnFJUWNDUUFKQUFrQWdDa1VFUUNBUFFRbElJQVVwQThqcEFVS0JnSUFJVkhJTkFpQW9LQUlBSWdKQkNHb2hFaUFDS0FJRUlRcEJBQ0VEUVFBaEFnTkFJQU1nQ25aRkJFQWdBaUFTSUFOQkEzUnFMUUFDUVJaTGFpRUNJQU5CQVdvaEF3d0JDd3NnQlVFQU5nS2M2d0VnQWtFSUlBcHJkRUVVVHcwQkRBTUxJQVZCQURZQ25Pc0JDeUFFSUFVb0F2RHFBU0lETmdMY0FTQUpJQTVxSVJZZ0F5QUZLQUtBNndGcUlSY0NRQ0FQUlFSQUlBNGhCd3dCQ3lBRktBSzQ2UUVoR2lBRktBSzA2UUVoR0NBRktBS3c2UUVoRWlBRlFRRTJBb1RxQVVFQUlRTURRQ0FEUVFOSEJFQWdCQ0FEUVFKMElnSnFJQUlnQldwQnJOQUJhaWdDQURZQ1pDQURRUUZxSVFNTUFRc0xRV3doQ1NBRVFUaHFJZ0lnQnlBR0VBMUJpSDlMRFFOQkNDQVBJQTlCQ0U0YklSOGdOQ0FDSUFVb0FnQVFIaUF6SUFJZ0JTZ0NDQkFlSURJZ0FpQUZLQUlFRUI0Z0RpQVNheUVaUVFBaENBTkFJQVJCT0dvUUQwRURSaUFJSUI5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdkQkVIWWlFVUgvQVhFaEN5QUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZ3hCRUhZaUlVSC9BWEVoRUNBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUVlnUVVJZ2lDQkFRaUNJcHlFREFrQWdRa0lRaUtjaUNrSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lLYXlJTklBSWdBaUFOU3hzaUV5QUthallDUENBR0lBUW9BamdnQ25SQkFDQVRhM1lnQWlBVGF5SVRkR29oQ2lBRVFUaHFFQThhSUFJZ0RVME5BU0FFSUFRb0Fqd2lBaUFUYWpZQ1BDQUVLQUk0SUFKMFFRQWdFMnQySUFwcUlRb01BUXNnQkNBQ0lBUW9BandpRFdvMkFqd2dCQ2dDT0NBTmRFRUFJQXByZGlBR2FpRUtJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQW8yQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBREJFQWdCQ2dDWkNFS0RBTUxJQVFvQW1naENnd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQVlnQTBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdaRklBWnFJUW9nQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlBbzJBbVFMcHlFQ0lFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQkJxTmdJOElBUW9BamdnQm5SQkFDQWhhM1lnQW1vaEFnc2dDeUFRYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lHSUF0cU5nSThJQVFvQWpnZ0JuUkJBQ0FSYTNZZ0Eyb2hBd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lCa0VBSUFkQkdIWWlDeUFFS0FJOGFpSVFhM1lnQzBFQ2RFR2dIV29vQWdCeElBZEIvLzhEY1dvMkFrd2dCQ0FRSUF4QkdIWWlCMm9pQ3pZQ1BDQUVJQWRCQW5SQm9CMXFLQUlBSUFaQkFDQUxhM1p4SUF4Qi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ1pCR0hZaUJ5QUVLQUk4YWlJTE5nSThJQVFnQjBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUF0cmRuRWdCa0gvL3dOeGFqWUNWQ0FFUWZBQWFpQUlRUXhzYWlJR0lBbzJBZ2dnQmlBQ05nSUVJQVlnQXpZQ0FDQUlRUUZxSVFnZ0F5QVphaUFDYWlFWkRBRUxDeUFJSUI5SURRTWdGa0VnYXlFaElBNGhCd05BSUFSQk9Hb1FEMEVEUmlBSUlBOU9ja1VFUUNBRUtBSlFJQVFvQWt4QkEzUnFLUUlBSWtDbklnWkJFSFlpSTBIL0FYRWhDaUFFS0FKZ0lBUW9BbHhCQTNScUtRSUFJa0duSWcxQkVIWWlJRUgvQVhFaEV5QUVLQUpZSUFRb0FsUkJBM1JxS1FJQUlrSkNJSWluSVFNZ1FVSWdpQ0JBUWlDSXB5RUxBa0FnUWtJUWlLY2lERUgvQVhFaUFrRUNUd1JBQWtBZ0FrRVpTU0EvUW9HQWdCQlVja1VFUUNBRVFTQWdCQ2dDUENJTWF5SVJJQUlnQWlBUlN4c2lFQ0FNYWpZQ1BDQURJQVFvQWpnZ0RIUkJBQ0FRYTNZZ0FpQVFheUlNZEdvaEVDQUVRVGhxRUE4YUlBSWdFVTBOQVNBRUlBUW9BandpQWlBTWFqWUNQQ0FFS0FJNElBSjBRUUFnREd0MklCQnFJUkFNQVFzZ0JDQUNJQVFvQWp3aUVHbzJBandnQkNnQ09DQVFkRUVBSUF4cmRpQURhaUVRSUFSQk9Hb1FEeG9MSUFRcEFtUWhSQ0FFSUJBMkFtUWdCQ0JFTndKb0RBRUxBa0FnQWtVRVFDQUxCRUFnQkNnQ1pDRVFEQU1MSUFRb0FtZ2hFQXdCQ3lBRUlBUW9BandpQWtFQmFqWUNQQUovSUFNZ0MwVnFJQVFvQWpnZ0FuUkJIM1pxSWdKQkEwWUVRQ0FFS0FKa1FRRnJEQUVMSUFKQkFuUWdCR29vQW1RTElnTkZJQU5xSVJBZ0FrRUJSd1JBSUFRZ0JDZ0NhRFlDYkFzTElBUWdCQ2dDWkRZQ2FDQUVJQkEyQW1RTHB5RU1JRUZDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUJOcU5nSThJQVFvQWpnZ0FuUkJBQ0FnYTNZZ0RHb2hEQXNnQ2lBVGFrRVVUd1JBSUFSQk9Hb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJQ0lBcHFOZ0k4SUFRb0FqZ2dBblJCQUNBamEzWWdDMm9oQ3dzZ0JFRTRhaEFQR2lBRUlBUW9BamdpQWtFQUlBWkJHSFlpQXlBRUtBSThhaUlLYTNZZ0EwRUNkRUdnSFdvb0FnQnhJQVpCLy84RGNXbzJBa3dnQkNBS0lBMUJHSFlpQTJvaUJqWUNQQ0FFSUFOQkFuUkJvQjFxS0FJQUlBSkJBQ0FHYTNaeElBMUIvLzhEY1dvMkFsd2dCRUU0YWhBUEdpQUVJRUtuSWdKQkdIWWlBeUFFS0FJOGFpSUdOZ0k4SUFRZ0EwRUNkRUdnSFdvb0FnQWdCQ2dDT0VFQUlBWnJkbkVnQWtILy93TnhhallDVkFKQUFrQUNRQ0FFS0FMY0FTSURJQVJCOEFCcUlBaEJCM0ZCREd4cUloTW9BZ0FpRVdvaUl5QVhTdzBBSUFjZ0V5Z0NCQ0lOSUJGcUlncHFJQ0ZMRFFBZ0NrRWdhaUFXSUFkclRRMEJDeUFFSUJNb0FnZzJBaGdnQkNBVEtRSUFOd01RSUFjZ0ZpQUVRUkJxSUFSQjNBRnFJQmNnRWlBWUlCb1FIeUVLREFFTElBY2dFV29oQWlBVEtBSUlJUVlnQnlBREtRQUFOd0FBSUFjZ0F5a0FDRGNBQ0FKQUlCRkJFVWtOQUNBSElBTXBBQkEzQUJBZ0J5QURLUUFZTndBWUlCRkJFR3RCRVVnTkFDQURRUkJxSVFNZ0IwRWdhaUVSQTBBZ0VTQURLUUFRTndBQUlCRWdBeWtBR0RjQUNDQVJJQU1wQUNBM0FCQWdFU0FES1FBb053QVlJQU5CSUdvaEF5QVJRU0JxSWhFZ0Fra05BQXNMSUFJZ0Jtc2hBeUFFSUNNMkF0d0JJQUlnRW1zZ0Jra0VRQ0FHSUFJZ0dHdExEUWNnR2lBYUlBTWdFbXNpQTJvaUVTQU5hazhFUUNBQ0lCRWdEUkFLR2d3Q0N5QURJQTFxSVEwZ0FpQVJRUUFnQTJzUUNpQURheUVDSUJJaEF3c2dCa0VRVHdSQUlBSWdBeWtBQURjQUFDQUNJQU1wQUFnM0FBZ2dEVUVSU0EwQklBSWdEV29oQmlBQ1FSQnFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBR1NRMEFDd3dCQ3dKQUlBWkJCMDBFUUNBQ0lBTXRBQUE2QUFBZ0FpQURMUUFCT2dBQklBSWdBeTBBQWpvQUFpQUNJQU10QUFNNkFBTWdBaUFESUFaQkFuUWlCa0hBSG1vb0FnQnFJZ01vQUFBMkFBUWdBeUFHUWVBZWFpZ0NBR3NoQXd3QkN5QUNJQU1wQUFBM0FBQUxJQTFCQ1VrTkFDQUNJQTFxSVJFZ0FrRUlhaUlHSUFOQkNHb2lBMnRCRDB3RVFBTkFJQVlnQXlrQUFEY0FBQ0FEUVFocUlRTWdCa0VJYWlJR0lCRkpEUUFNQWdzQUN5QUdJQU1wQUFBM0FBQWdCaUFES1FBSU53QUlJQTFCR1VnTkFDQUNRUmhxSVFJRFFDQUNJQU1wQUJBM0FBQWdBaUFES1FBWU53QUlJQUlnQXlrQUlEY0FFQ0FDSUFNcEFDZzNBQmdnQTBFZ2FpRURJQUpCSUdvaUFpQVJTUTBBQ3dzZ0NrR0lmMHNFUUNBS0lRa01CZ1VnRXlBUU5nSUlJQk1nRERZQ0JDQVRJQXMyQWdBZ0NFRUJhaUVJSUFjZ0Ntb2hCeUFMSUJscUlBeHFJUmtNQWdzQUN3c2dDQ0FQU0EwRElBZ2dIMnNoQmdOQUFrQWdCaUFQVGdSQVFRQWhBd05BSUFOQkEwWU5BaUFGSUFOQkFuUWlBbXBCck5BQmFpQUNJQVJxS0FKa05nSUFJQU5CQVdvaEF3d0FDd0FMQWtBQ1FBSkFJQVFvQXR3QklnTWdCRUh3QUdvZ0JrRUhjVUVNYkdvaUNDZ0NBQ0lNYWlJUUlCZExEUUFnQnlBSUtBSUVJZ3NnREdvaUNtb2dJVXNOQUNBS1FTQnFJQllnQjJ0TkRRRUxJQVFnQ0NnQ0NEWUNLQ0FFSUFncEFnQTNBeUFnQnlBV0lBUkJJR29nQkVIY0FXb2dGeUFTSUJnZ0doQWZJUW9NQVFzZ0J5QU1haUVDSUFnb0FnZ2hDQ0FISUFNcEFBQTNBQUFnQnlBREtRQUlOd0FJQWtBZ0RFRVJTUTBBSUFjZ0F5a0FFRGNBRUNBSElBTXBBQmczQUJnZ0RFRVFhMEVSU0EwQUlBTkJFR29oQXlBSFFTQnFJUXdEUUNBTUlBTXBBQkEzQUFBZ0RDQURLUUFZTndBSUlBd2dBeWtBSURjQUVDQU1JQU1wQUNnM0FCZ2dBMEVnYWlFRElBeEJJR29pRENBQ1NRMEFDd3NnQWlBSWF5RURJQVFnRURZQzNBRWdBaUFTYXlBSVNRUkFJQWdnQWlBWWEwc05CeUFhSUJvZ0F5QVNheUlEYWlJTUlBdHFUd1JBSUFJZ0RDQUxFQW9hREFJTElBTWdDMm9oQ3lBQ0lBeEJBQ0FEYXhBS0lBTnJJUUlnRWlFREN5QUlRUkJQQkVBZ0FpQURLUUFBTndBQUlBSWdBeWtBQ0RjQUNDQUxRUkZJRFFFZ0FpQUxhaUVJSUFKQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFJZ0F5MEFBRG9BQUNBQ0lBTXRBQUU2QUFFZ0FpQURMUUFDT2dBQ0lBSWdBeTBBQXpvQUF5QUNJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBSWdBeWtBQURjQUFBc2dDMEVKU1EwQUlBSWdDMm9oRENBQ1FRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0RFa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dDMEVaU0EwQUlBSkJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBeEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0dCU0FHUVFGcUlRWWdCeUFLYWlFSERBSUxBQXNMSUFRb0F0d0JJUU1MUWJwL0lRa2dGeUFEYXlJQ0lCWWdCMnRMRFFJZ0J3Ui9JQWNnQXlBQ0VBSWdBbW9GUVFBTElBNXJJUWtNQWdzZ0JVRUFOZ0tjNndFTElBUWdCU2dDOE9vQklnTTJBdHdCSUFrZ0Rtb2hEQ0FESUFVb0FvRHJBV29oRUFKQUlBOUZCRUFnRGlFR0RBRUxJQVVvQXJqcEFTRU5JQVVvQXJUcEFTRVRJQVVvQXJEcEFTRVNJQVZCQVRZQ2hPb0JRUUFoQXdOQUlBTkJBMGNFUUNBRUlBTkJBblFpQW1vZ0FpQUZha0dzMEFGcUtBSUFOZ0tjQVNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUWZBQWFpSUNJQWNnQmhBTlFZaC9TdzBCSURFZ0FpQUZLQUlBRUI0Z01DQUNJQVVvQWdnUUhpQXZJQUlnQlNnQ0JCQWVJQXhCSUdzaEdDQU9JUVlEUUNBRUtBS0lBU0FFS0FLRUFVRURkR29wQWdBaVFLY2lDa0VRZGlJWlFmOEJjU0VMSUFRb0FwZ0JJQVFvQXBRQlFRTjBhaWtDQUNKQnB5SVdRUkIySWg5Qi93RnhJUm9nQkNnQ2tBRWdCQ2dDakFGQkEzUnFLUUlBSWtKQ0lJaW5JUWNnUVVJZ2lDQkFRaUNJcHlFREFrQWdRa0lRaUtjaUNFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NkQ0lJYXlJUklBSWdBaUFSU3hzaUZ5QUlhallDZENBSElBUW9BbkFnQ0hSQkFDQVhhM1lnQWlBWGF5SVhkR29oQ0NBRVFmQUFhaEFQR2lBQ0lCRk5EUUVnQkNBRUtBSjBJZ0lnRjJvMkFuUWdCQ2dDY0NBQ2RFRUFJQmRyZGlBSWFpRUlEQUVMSUFRZ0FpQUVLQUowSWhGcU5nSjBJQVFvQW5BZ0VYUkJBQ0FJYTNZZ0Iyb2hDQ0FFUWZBQWFoQVBHZ3NnQkNrQ25BRWhSQ0FFSUFnMkFwd0JJQVFnUkRjQ29BRU1BUXNDUUNBQ1JRUkFJQU1FUUNBRUtBS2NBU0VJREFNTElBUW9BcUFCSVFnTUFRc2dCQ0FFS0FKMElnSkJBV28yQW5RQ2Z5QUhJQU5GYWlBRUtBSndJQUowUVI5MmFpSUNRUU5HQkVBZ0JDZ0NuQUZCQVdzTUFRc2dBa0VDZENBRWFpZ0NuQUVMSWdkRklBZHFJUWdnQWtFQlJ3UkFJQVFnQkNnQ29BRTJBcVFCQ3dzZ0JDQUVLQUtjQVRZQ29BRWdCQ0FJTmdLY0FRdW5JUUlnUVVLQWdQd0hnMUJGQkVBZ0JDQUVLQUowSWdjZ0dtbzJBblFnQkNnQ2NDQUhkRUVBSUI5cmRpQUNhaUVDQ3lBTElCcHFRUlJQQkVBZ0JFSHdBR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ2RDSUhJQXRxTmdKMElBUW9BbkFnQjNSQkFDQVphM1lnQTJvaEF3c2dCRUh3QUdvUUR4b2dCQ0FFS0FKd0lnZEJBQ0FLUVJoMklnc2dCQ2dDZEdvaUdtdDJJQXRCQW5SQm9CMXFLQUlBY1NBS1FmLy9BM0ZxTmdLRUFTQUVJQm9nRmtFWWRpSUthaUlMTmdKMElBUWdDa0VDZEVHZ0hXb29BZ0FnQjBFQUlBdHJkbkVnRmtILy93TnhhallDbEFFZ0JFSHdBR29RRHhvZ0JDQkNweUlIUVJoMklnb2dCQ2dDZEdvaUN6WUNkQ0FFSUFwQkFuUkJvQjFxS0FJQUlBUW9BbkJCQUNBTGEzWnhJQWRCLy84RGNXbzJBb3dCSUFRZ0F6WUNPQ0FFSUFJMkFqd2dCQ0FJTmdKQUFrQUNRQUpBSUFRb0F0d0JJZ3NnQTJvaUZpQVFTdzBBSUFZZ0FpQURhaUlLYWlBWVN3MEFJQXBCSUdvZ0RDQUdhMDBOQVFzZ0JDQUVRVUJyS0FJQU5nSUlJQVFnQkNrRE9EY0RBQ0FHSUF3Z0JDQUVRZHdCYWlBUUlCSWdFeUFORUI4aENnd0JDeUFESUFacUlRY2dCaUFMS1FBQU53QUFJQVlnQ3lrQUNEY0FDQUpBSUFOQkVVa05BQ0FHSUFzcEFCQTNBQkFnQmlBTEtRQVlOd0FZSUFOQkVHdEJFVWdOQUNBTFFSQnFJUU1nQmtFZ2FpRUxBMEFnQ3lBREtRQVFOd0FBSUFzZ0F5a0FHRGNBQ0NBTElBTXBBQ0EzQUJBZ0N5QURLUUFvTndBWUlBTkJJR29oQXlBTFFTQnFJZ3NnQjBrTkFBc0xJQWNnQ0dzaEF5QUVJQlkyQXR3QklBY2dFbXNnQ0VrRVFDQUlJQWNnRTJ0TERRUWdEU0FOSUFNZ0Vtc2lBMm9pQ3lBQ2FrOEVRQ0FISUFzZ0FoQUtHZ3dDQ3lBSElBdEJBQ0FEYXhBS0lBUWdBaUFEYWlJQ05nSThJQU5ySVFjZ0VpRURDeUFJUVJCUEJFQWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQ0FDUVJGSURRRWdBaUFIYWlFSUlBZEJFR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBaEpEUUFMREFFTEFrQWdDRUVIVFFSQUlBY2dBeTBBQURvQUFDQUhJQU10QUFFNkFBRWdCeUFETFFBQ09nQUNJQWNnQXkwQUF6b0FBeUFISUFNZ0NFRUNkQ0lJUWNBZWFpZ0NBR29pQXlnQUFEWUFCQ0FESUFoQjRCNXFLQUlBYXlFRERBRUxJQWNnQXlrQUFEY0FBQXNnQWtFSlNRMEFJQUlnQjJvaEN5QUhRUWhxSWdnZ0EwRUlhaUlEYTBFUFRBUkFBMEFnQ0NBREtRQUFOd0FBSUFOQkNHb2hBeUFJUVFocUlnZ2dDMGtOQUF3Q0N3QUxJQWdnQXlrQUFEY0FBQ0FJSUFNcEFBZzNBQWdnQWtFWlNBMEFJQWRCR0dvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQXRKRFFBTEN5QUtRWWgvU3dSQUlBb2hDUXdEQ3lBR0lBcHFJUVlnQkVId0FHb1FEeUVESUE5QkFXc2lEdzBBQzBFQUlRSWdBMEVDU1EwQkEwQWdBa0VEUndSQUlBVWdBa0VDZENJRGFrR3MwQUZxSUFNZ0JHb29BcHdCTmdJQUlBSkJBV29oQWd3QkN3c2dCQ2dDM0FFaEF3dEJ1bjhoQ1NBUUlBTnJJZ0lnRENBR2Ewc05BQ0FHQkg4Z0JpQURJQUlRQWlBQ2FnVkJBQXNnRG1zaENRc2dDVUdJZjBzTkJnc0NRQ0FGS0FMczZnRkZEUUFnQlNBRktRT0k2Z0VnQ2ExOE53T0k2Z0VDUUNBRktBTFE2Z0VpQWlBSmFpSUlRUjlOQkVBZ0RrVU5BU0FDSUNKcUlBNGdDUkFDR2lBRktBTFE2Z0VnQ1dvaENBd0JDeUFPSVFNZ0FnUkFJQUlnSW1vZ0EwRWdJQUpyRUFJYUlBVW9BdERxQVNFQ0lBVkJBRFlDME9vQklBVWdCU2tEa09vQklBVXBBTERxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRGtPb0JJQVVnQlNrRG1Pb0JJQVVwQUxqcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RtT29CSUFVZ0JTa0RvT29CSUFVcEFNRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEb09vQklBVWdCU2tEcU9vQklBVXBBTWpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRHFPb0JJQU1nQW10QklHb2hBd3NnQ1NBT2FpSUNJQU5CSUdwUEJFQWdBa0VnYXlFR0lBVXBBNmpxQVNFL0lBVXBBNkRxQVNGQUlBVXBBNWpxQVNGQklBVXBBNURxQVNGQ0EwQWdBeWtBR0VMUDF0Tyswc2VyMlVKK0lEOThRaCtKUW9lVnI2K1l0dDZibm45K0lUOGdBeWtBRUVMUDF0Tyswc2VyMlVKK0lFQjhRaCtKUW9lVnI2K1l0dDZibm45K0lVQWdBeWtBQ0VMUDF0Tyswc2VyMlVKK0lFRjhRaCtKUW9lVnI2K1l0dDZibm45K0lVRWdBeWtBQUVMUDF0Tyswc2VyMlVKK0lFSjhRaCtKUW9lVnI2K1l0dDZibm45K0lVSWdBMEVnYWlJRElBWk5EUUFMSUFVZ1B6Y0RxT29CSUFVZ1FEY0RvT29CSUFVZ1FUY0RtT29CSUFVZ1FqY0RrT29CQ3lBQ0lBTk5EUUVnSWlBRElBSWdBMnNpQ0JBQ0dnc2dCU0FJTmdMUTZnRUxJRFVnRldzaEF5QVZJQnRxSVFJZ0NTQU9haUVPSUFRb0FqQkZEUUFMSUNrcEF3QWlQMEovVVNBL0lBNGdIV3VzVVhKRkJFQkJiQ0VKREFZTElBVW9BdURwQVFSQVFXb2hDU0FEUVFSSkRRWWdCU2dDNk9vQlJRUkFJQ0lnQlNnQzBPb0JhaUVLQW40Z0JTa0RpT29CSWo5Q0lGb0VRQ0FGS1FPWTZnRWlRRUlIaVNBRktRT1E2Z0VpUVVJQmlYd2dCU2tEb09vQklrSkNESWw4SUFVcEE2anFBU0pEUWhLSmZDQkJRcy9XMDc3U3g2dlpRbjVDSDRsQ2g1V3ZyNWkyM3B1ZWYzNkZRb2VWcjYrWXR0NmJubjkrUXAyanRlcURzWTJLK2dCOUlFQkN6OWJUdnRMSHE5bENma0lmaVVLSGxhK3ZtTGJlbTU1L2ZvVkNoNVd2cjVpMjNwdWVmMzVDbmFPMTZvT3hqWXI2QUgwZ1FrTFAxdE8rMHNlcjJVSitRaCtKUW9lVnI2K1l0dDZibm45K2hVS0hsYSt2bUxiZW01NS9ma0tkbzdYcWc3R05pdm9BZlNCRFFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5REFFTElBVXBBNkRxQVVMRno5bXk4ZVc2NmlkOEN5QS9mQ0UvSUNJaEJnTkFJQW9nQmtFSWFpSUhUd1JBSUFZcEFBQkN6OWJUdnRMSHE5bENma0lmaVVLSGxhK3ZtTGJlbTU1L2ZpQS9oVUliaVVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0UvSUFjaEJnd0JDd3NDUUNBS0lBWkJCR29pQ0VrRVFDQUdJUWdNQVFzZ0JqVUFBRUtIbGErdm1MYmVtNTUvZmlBL2hVSVhpVUxQMXRPKzBzZXIyVUorUXZuejNmR1o5cG1yRm53aFB3c0RRQ0FJSUFwSkJFQWdDREVBQUVMRno5bXk4ZVc2NmlkK0lEK0ZRZ3VKUW9lVnI2K1l0dDZibm45K0lUOGdDRUVCYWlFSURBRUxDeUFDS0FBQUlEOUNJWWdnUDRWQ3o5YlR2dExIcTlsQ2ZpSS9RaDJJSUQrRlF2bnozZkdaOXBtckZuNGlQMElnaUNBL2hhZEhEUWNMSUFOQkJHc2hBeUFDUVFScUlRSUxJQTRnSFdzaUNVR0pmMDhOQkNBQklBbHJJUUVnQ1NBZGFpRWRRUUVoUGd3QkN3dEJ1SDhoQnlBRERRUWdIU0FBYXlFSERBUUxRV3doQ1F3QkMwRzRmeUVKQzBHNGZ5RUhJQWxCZGtZZ1BuRU5BUXNnQ1NFSEN5Z0NBQTBBSUFWQi9Pb0JhaWdDQUNFQklBVkIrT29CYWlnQ0FDRUFJQVVRR0NBRktBS3c2d0VnQUNBQkVCTWdCVUVBTmdLdzZ3RWdCU2dDcE9zQklnSUVRQUpBQWtBQ1FBSkFJQUlvQWdBaUF3UkFJQUJGRFFJZ0FTQURJQUFSQWdBTUFRc2dBRVVOQWdzZ0FTQUNJQUFSQWdBTUFnc2dBeEFHQ3lBQ0VBWUxJQVZCQURZQ3BPc0JDeUFBQkVBZ0FTQUZJQUFSQWdBTUFRc2dCUkFHQ3lBRVFlQUJhaVFBSUFjTEM2Z1ZDUUJCaUFnTERRRUFBQUFCQUFBQUFnQUFBQUlBUWFBSUM3TUdBUUFBQUFFQUFBQUNBQUFBQWdBQUFDWUFBQUNDQUFBQUlRVUFBRW9BQUFCbkNBQUFKZ0FBQU1BQkFBQ0FBQUFBU1FVQUFFb0FBQUMrQ0FBQUtRQUFBQ3dDQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBTHdBQUFNb0NBQUNBQUFBQWlnVUFBRW9BQUFDRUNRQUFOUUFBQUhNREFBQ0FBQUFBblFVQUFFb0FBQUNnQ1FBQVBRQUFBSUVEQUFDQUFBQUE2d1VBQUVzQUFBQStDZ0FBUkFBQUFKNERBQUNBQUFBQVRRWUFBRXNBQUFDcUNnQUFTd0FBQUxNREFBQ0FBQUFBd1FZQUFFMEFBQUFmRFFBQVRRQUFBRk1FQUFDQUFBQUFJd2dBQUZFQUFBQ21Ed0FBVkFBQUFKa0VBQUNBQUFBQVN3a0FBRmNBQUFDeEVnQUFXQUFBQU5vRUFBQ0FBQUFBYndrQUFGMEFBQUFqRkFBQVZBQUFBRVVGQUFDQUFBQUFWQW9BQUdvQUFBQ01GQUFBYWdBQUFLOEZBQUNBQUFBQWRna0FBSHdBQUFCT0VBQUFmQUFBQU5JQ0FBQ0FBQUFBWXdjQUFKRUFBQUNRQndBQWtnQUFBQUFBQUFBQkFBQUFBUUFBQUFVQUFBQU5BQUFBSFFBQUFEMEFBQUI5QUFBQS9RQUFBUDBCQUFEOUF3QUEvUWNBQVAwUEFBRDlId0FBL1Q4QUFQMS9BQUQ5L3dBQS9mOEJBUDMvQXdEOS93Y0EvZjhQQVAzL0h3RDkvejhBL2Y5L0FQMy8vd0Q5Ly84Qi9mLy9BLzMvL3dmOS8vOFAvZi8vSC8zLy96LzkvLzkvQUFBQUFBRUFBQUFDQUFBQUF3QUFBQVFBQUFBRkFBQUFCZ0FBQUFjQUFBQUlBQUFBQ1FBQUFBb0FBQUFMQUFBQURBQUFBQTBBQUFBT0FBQUFEd0FBQUJBQUFBQVJBQUFBRWdBQUFCTUFBQUFVQUFBQUZRQUFBQllBQUFBWEFBQUFHQUFBQUJrQUFBQWFBQUFBR3dBQUFCd0FBQUFkQUFBQUhnQUFBQjhBQUFBREFBQUFCQUFBQUFVQUFBQUdBQUFBQndBQUFBZ0FBQUFKQUFBQUNnQUFBQXNBQUFBTUFBQUFEUUFBQUE0QUFBQVBBQUFBRUFBQUFCRUFBQUFTQUFBQUV3QUFBQlFBQUFBVkFBQUFGZ0FBQUJjQUFBQVlBQUFBR1FBQUFCb0FBQUFiQUFBQUhBQUFBQjBBQUFBZUFBQUFId0FBQUNBQUFBQWhBQUFBSWdBQUFDTUFBQUFsQUFBQUp3QUFBQ2tBQUFBckFBQUFMd0FBQURNQUFBQTdBQUFBUXdBQUFGTUFBQUJqQUFBQWd3QUFBQU1CQUFBREFnQUFBd1FBQUFNSUFBQURFQUFBQXlBQUFBTkFBQUFEZ0FBQUF3QUJBRUhnRHd0UkFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQXdBQUFBTUFBQUFFQUFBQUJBQUFBQVVBQUFBSEFBQUFDQUFBQUFrQUFBQUtBQUFBQ3dBQUFBd0FBQUFOQUFBQURnQUFBQThBQUFBUUFFSEVFQXVMQVFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBU0FBQUFGQUFBQUJZQUFBQVlBQUFBSEFBQUFDQUFBQUFvQUFBQU1BQUFBRUFBQUFDQUFBQUFBQUVBQUFBQ0FBQUFCQUFBQUFnQUFBQVFBQUFBSUFBQUFFQUFBQUNBQUFBQUFBRUFRWkFTQytZRUFRQUFBQUVBQUFBQkFBQUFBUUFBQUFJQUFBQUNBQUFBQXdBQUFBTUFBQUFFQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBQkFBQUFCQUFBQUFnQUFBQUFBQUFBQVFBQkFRWUFBQUFBQUFBRUFBQUFBQkFBQUFRQUFBQUFJQUFBQlFFQUFBQUFBQUFGQXdBQUFBQUFBQVVFQUFBQUFBQUFCUVlBQUFBQUFBQUZCd0FBQUFBQUFBVUpBQUFBQUFBQUJRb0FBQUFBQUFBRkRBQUFBQUFBQUFZT0FBQUFBQUFCQlJBQUFBQUFBQUVGRkFBQUFBQUFBUVVXQUFBQUFBQUNCUndBQUFBQUFBTUZJQUFBQUFBQUJBVXdBQUFBSUFBR0JVQUFBQUFBQUFjRmdBQUFBQUFBQ0FZQUFRQUFBQUFLQmdBRUFBQUFBQXdHQUJBQUFDQUFBQVFBQUFBQUFBQUFCQUVBQUFBQUFBQUZBZ0FBQUNBQUFBVUVBQUFBQUFBQUJRVUFBQUFnQUFBRkJ3QUFBQUFBQUFVSUFBQUFJQUFBQlFvQUFBQUFBQUFGQ3dBQUFBQUFBQVlOQUFBQUlBQUJCUkFBQUFBQUFBRUZFZ0FBQUNBQUFRVVdBQUFBQUFBQ0JSZ0FBQUFnQUFNRklBQUFBQUFBQXdVb0FBQUFBQUFHQkVBQUFBQVFBQVlFUUFBQUFDQUFCd1dBQUFBQUFBQUpCZ0FDQUFBQUFBc0dBQWdBQURBQUFBUUFBQUFBRUFBQUJBRUFBQUFnQUFBRkFnQUFBQ0FBQUFVREFBQUFJQUFBQlFVQUFBQWdBQUFGQmdBQUFDQUFBQVVJQUFBQUlBQUFCUWtBQUFBZ0FBQUZDd0FBQUNBQUFBVU1BQUFBQUFBQUJnOEFBQUFnQUFFRkVnQUFBQ0FBQVFVVUFBQUFJQUFDQlJnQUFBQWdBQUlGSEFBQUFDQUFBd1VvQUFBQUlBQUVCVEFBQUFBQUFCQUdBQUFCQUFBQUR3WUFnQUFBQUFBT0JnQkFBQUFBQUEwR0FDQUFRWUFYQzRjQ0FRQUJBUVVBQUFBQUFBQUZBQUFBQUFBQUJnUTlBQUFBQUFBSkJmMEJBQUFBQUE4Ri9YOEFBQUFBRlFYOS94OEFBQUFEQlFVQUFBQUFBQWNFZlFBQUFBQUFEQVg5RHdBQUFBQVNCZjMvQXdBQUFCY0YvZjkvQUFBQUJRVWRBQUFBQUFBSUJQMEFBQUFBQUE0Ri9UOEFBQUFBRkFYOS93OEFBQUFDQlFFQUFBQVFBQWNFZlFBQUFBQUFDd1g5QndBQUFBQVJCZjMvQVFBQUFCWUYvZjgvQUFBQUJBVU5BQUFBRUFBSUJQMEFBQUFBQUEwRi9SOEFBQUFBRXdYOS93Y0FBQUFCQlFFQUFBQVFBQVlFUFFBQUFBQUFDZ1g5QXdBQUFBQVFCZjMvQUFBQUFCd0YvZi8vRHdBQUd3WDkvLzhIQUFBYUJmMy8vd01BQUJrRi9mLy9BUUFBR0FYOS8vOEFRWkFaQzRZRUFRQUJBUVlBQUFBQUFBQUdBd0FBQUFBQUFBUUVBQUFBSUFBQUJRVUFBQUFBQUFBRkJnQUFBQUFBQUFVSUFBQUFBQUFBQlFrQUFBQUFBQUFGQ3dBQUFBQUFBQVlOQUFBQUFBQUFCaEFBQUFBQUFBQUdFd0FBQUFBQUFBWVdBQUFBQUFBQUJoa0FBQUFBQUFBR0hBQUFBQUFBQUFZZkFBQUFBQUFBQmlJQUFBQUFBQUVHSlFBQUFBQUFBUVlwQUFBQUFBQUNCaThBQUFBQUFBTUdPd0FBQUFBQUJBWlRBQUFBQUFBSEJvTUFBQUFBQUFrR0F3SUFBQkFBQUFRRUFBQUFBQUFBQkFVQUFBQWdBQUFGQmdBQUFBQUFBQVVIQUFBQUlBQUFCUWtBQUFBQUFBQUZDZ0FBQUFBQUFBWU1BQUFBQUFBQUJnOEFBQUFBQUFBR0VnQUFBQUFBQUFZVkFBQUFBQUFBQmhnQUFBQUFBQUFHR3dBQUFBQUFBQVllQUFBQUFBQUFCaUVBQUFBQUFBRUdJd0FBQUFBQUFRWW5BQUFBQUFBQ0Jpc0FBQUFBQUFNR013QUFBQUFBQkFaREFBQUFBQUFGQm1NQUFBQUFBQWdHQXdFQUFDQUFBQVFFQUFBQU1BQUFCQVFBQUFBUUFBQUVCUUFBQUNBQUFBVUhBQUFBSUFBQUJRZ0FBQUFnQUFBRkNnQUFBQ0FBQUFVTEFBQUFBQUFBQmc0QUFBQUFBQUFHRVFBQUFBQUFBQVlVQUFBQUFBQUFCaGNBQUFBQUFBQUdHZ0FBQUFBQUFBWWRBQUFBQUFBQUJpQUFBQUFBQUJBR0F3QUJBQUFBRHdZRGdBQUFBQUFPQmdOQUFBQUFBQTBHQXlBQUFBQUFEQVlERUFBQUFBQUxCZ01JQUFBQUFBb0dBd1FBUWFRZEM5a0JBUUFBQUFNQUFBQUhBQUFBRHdBQUFCOEFBQUEvQUFBQWZ3QUFBUDhBQUFEL0FRQUEvd01BQVA4SEFBRC9Ed0FBL3g4QUFQOC9BQUQvZndBQS8vOEFBUC8vQVFELy93TUEvLzhIQVAvL0R3RC8veDhBLy84L0FQLy9md0QvLy84QS8vLy9BZi8vL3dQLy8vOEgvLy8vRC8vLy94Ly8vLzgvLy8vL2Z3QUFBQUFCQUFBQUFnQUFBQVFBQUFBQUFBQUFBZ0FBQUFRQUFBQUlBQUFBQUFBQUFBRUFBQUFDQUFBQUFRQUFBQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBZ0FBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0JCZ0I4TEE0QVJBUT09Ijt2YXIgdHQ9bmV3IEdBLEl0PSExO2FzeW5jIGZ1bmN0aW9uIERJKEEsZSl7bGV0IHQ9bnVsbDt0eXBlb2YgQSE9InN0cmluZyI/dD1BLmhyZWY6QS5zdGFydHNXaXRoKCJodHRwIik/dD1BOnQ9YCR7ZX0vJHtBfWAsdC5lbmRzV2l0aCgiLmpzIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtMykpLHQuZW5kc1dpdGgoIi53YXNtIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtNSkpO2xldCBJPWAke3R9Lndhc21gLHI9YXdhaXQgUkEuZ2V0KGAke0l9LnpzdGAse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIifSk7SXR8fChhd2FpdCB0dC5pbml0KCksSXQ9ITApO2xldCBnPXR0LmRlY29kZShuZXcgVWludDhBcnJheShyLmRhdGEpKS5idWZmZXI7cmV0dXJuKGF3YWl0IGltcG9ydChgJHt0fS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5Omd9KX12YXIgcnQ9REk7dmFyIFVBPW5ldyBNYXA7YXN5bmMgZnVuY3Rpb24geUkoQSxlKXtsZXQgdD1BLEk9QSxyPW51bGw7cmV0dXJuIHR5cGVvZiBBIT0ic3RyaW5nIiYmKHQ9bmV3IFVSTChBLmhyZWYpLEk9dC5ocmVmKSxVQS5oYXMoSSl8fFVBLnNldChJLGF3YWl0IHJ0KHQsZSkpLHI9VUEuZ2V0KEkpLHJ9dmFyIEc9eUk7dmFyIHdJPW5ldyBNYXAoW1siaW1hZ2UvanBlZyIsIkpQRUdJbWFnZUlPIl0sWyJpbWFnZS9wbmciLCJQTkdJbWFnZUlPIl0sWyJpbWFnZS90aWZmIiwiVElGRkltYWdlSU8iXSxbImltYWdlL3gtbXMtYm1wIiwiQk1QSW1hZ2VJTyJdLFsiaW1hZ2UveC1ibXAiLCJCTVBJbWFnZUlPIl0sWyJpbWFnZS9ibXAiLCJCTVBJbWFnZUlPIl0sWyJhcHBsaWNhdGlvbi9kaWNvbSIsIkdEQ01JbWFnZUlPIl1dKSxpZT13STt2YXIgcEk9bmV3IE1hcChbWyJibXAiLCJCTVBJbWFnZUlPIl0sWyJCTVAiLCJCTVBJbWFnZUlPIl0sWyJkY20iLCJHRENNSW1hZ2VJTyJdLFsiRENNIiwiR0RDTUltYWdlSU8iXSxbImdpcGwiLCJHaXBsSW1hZ2VJTyJdLFsiZ2lwbC5neiIsIkdpcGxJbWFnZUlPIl0sWyJoZGY1IiwiSERGNUltYWdlSU8iXSxbImpwZyIsIkpQRUdJbWFnZUlPIl0sWyJKUEciLCJKUEVHSW1hZ2VJTyJdLFsianBlZyIsIkpQRUdJbWFnZUlPIl0sWyJKUEVHIiwiSlBFR0ltYWdlSU8iXSxbIml3aSIsIldhc21JbWFnZUlPIl0sWyJpd2kuY2JvciIsIldhc21JbWFnZUlPIl0sWyJpd2kuY2Jvci56c3QiLCJXYXNtWnN0ZEltYWdlSU8iXSxbImxzbSIsIkxTTUltYWdlSU8iXSxbIm1uYyIsIk1JTkNJbWFnZUlPIl0sWyJNTkMiLCJNSU5DSW1hZ2VJTyJdLFsibW5jLmd6IiwiTUlOQ0ltYWdlSU8iXSxbIk1OQy5HWiIsIk1JTkNJbWFnZUlPIl0sWyJtbmMyIiwiTUlOQ0ltYWdlSU8iXSxbIk1OQzIiLCJNSU5DSW1hZ2VJTyJdLFsibWdoIiwiTUdISW1hZ2VJTyJdLFsibWd6IiwiTUdISW1hZ2VJTyJdLFsibWdoLmd6IiwiTUdISW1hZ2VJTyJdLFsibWhhIiwiTWV0YUltYWdlSU8iXSxbIm1oZCIsIk1ldGFJbWFnZUlPIl0sWyJtcmMiLCJNUkNJbWFnZUlPIl0sWyJuaWEiLCJOaWZ0aUltYWdlSU8iXSxbIm5paSIsIk5pZnRpSW1hZ2VJTyJdLFsibmlpLmd6IiwiTmlmdGlJbWFnZUlPIl0sWyJoZHIiLCJOaWZ0aUltYWdlSU8iXSxbIm5ycmQiLCJOcnJkSW1hZ2VJTyJdLFsiTlJSRCIsIk5ycmRJbWFnZUlPIl0sWyJuaGRyIiwiTnJyZEltYWdlSU8iXSxbIk5IRFIiLCJOcnJkSW1hZ2VJTyJdLFsicG5nIiwiUE5HSW1hZ2VJTyJdLFsiUE5HIiwiUE5HSW1hZ2VJTyJdLFsicGljIiwiQmlvUmFkSW1hZ2VJTyJdLFsiUElDIiwiQmlvUmFkSW1hZ2VJTyJdLFsidGlmIiwiVElGRkltYWdlSU8iXSxbIlRJRiIsIlRJRkZJbWFnZUlPIl0sWyJ0aWZmIiwiVElGRkltYWdlSU8iXSxbIlRJRkYiLCJUSUZGSW1hZ2VJTyJdLFsidnRrIiwiVlRLSW1hZ2VJTyJdLFsiVlRLIiwiVlRLSW1hZ2VJTyJdLFsiaXNxIiwiU2NhbmNvSW1hZ2VJTyJdLFsiSVNRIiwiU2NhbmNvSW1hZ2VJTyJdLFsiZmRmIiwiRkRGSW1hZ2VJTyJdLFsiRkRGIiwiRkRGSW1hZ2VJTyJdXSksZ2U9cEk7ZnVuY3Rpb24gRkkoQSl7bGV0IGU9QS5zbGljZSgoQS5sYXN0SW5kZXhPZigiLiIpLTE+Pj4wKSsyKTtpZihlLnRvTG93ZXJDYXNlKCk9PT0iZ3oiKXtsZXQgdD1BLnNsaWNlKDAsLTMpLmxhc3RJbmRleE9mKCIuIik7ZT1BLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKGUudG9Mb3dlckNhc2UoKT09PSJjYm9yIil7bGV0IHQ9QS5zbGljZSgwLC01KS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihlLnRvTG93ZXJDYXNlKCk9PT0ienN0Iil7bGV0IHQ9QS5zbGljZSgwLC0xMCkubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoZS50b0xvd2VyQ2FzZSgpPT09InppcCIpe2xldCB0PUEuc2xpY2UoMCwtNCkubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfXJldHVybiBlfXZhciBrQT1GSTt2YXIgU0k9WyJQTkdJbWFnZUlPIiwiTWV0YUltYWdlSU8iLCJUSUZGSW1hZ2VJTyIsIk5pZnRpSW1hZ2VJTyIsIkpQRUdJbWFnZUlPIiwiTnJyZEltYWdlSU8iLCJWVEtJbWFnZUlPIiwiQk1QSW1hZ2VJTyIsIkhERjVJbWFnZUlPIiwiTUlOQ0ltYWdlSU8iLCJNUkNJbWFnZUlPIiwiTFNNSW1hZ2VJTyIsIk1HSEltYWdlSU8iLCJCaW9SYWRJbWFnZUlPIiwiR2lwbEltYWdlSU8iLCJHRUFkd0ltYWdlSU8iLCJHRTRJbWFnZUlPIiwiR0U1SW1hZ2VJTyIsIkdEQ01JbWFnZUlPIiwiU2NhbmNvSW1hZ2VJTyIsIkZERkltYWdlSU8iLCJXYXNtSW1hZ2VJTyIsIldhc21ac3RkSW1hZ2VJTyJdLExBPVNJO3ZhciBOST17VGV4dEZpbGU6IkludGVyZmFjZVRleHRGaWxlIixCaW5hcnlGaWxlOiJJbnRlcmZhY2VCaW5hcnlGaWxlIixUZXh0U3RyZWFtOiJJbnRlcmZhY2VUZXh0U3RyZWFtIixCaW5hcnlTdHJlYW06IkludGVyZmFjZUJpbmFyeVN0cmVhbSIsSW1hZ2U6IkludGVyZmFjZUltYWdlIixNZXNoOiJJbnRlcmZhY2VNZXNoIixQb2x5RGF0YToiSW50ZXJmYWNlUG9seURhdGEiLEpzb25Db21wYXRpYmxlOiJJbnRlcmZhY2VKc29uQ29tcGF0aWJsZSJ9LHU9Tkk7dmFyIFJJPXtUZXh0OiJUZXh0IixCaW5hcnk6IkJpbmFyeSIsSW1hZ2U6IkltYWdlIixNZXNoOiJNZXNoIn0sUz1SSTt2YXIgR0k9e0ludDg6ImludDgiLFVJbnQ4OiJ1aW50OCIsSW50MTY6ImludDE2IixVSW50MTY6InVpbnQxNiIsSW50MzI6ImludDMyIixVSW50MzI6InVpbnQzMiIsSW50NjQ6ImludDY0IixVSW50NjQ6InVpbnQ2NCIsU2l6ZVZhbHVlVHlwZToidWludDY0IixJZGVudGlmaWVyVHlwZToidWludDY0IixJbmRleFZhbHVlVHlwZToiaW50NjQiLE9mZnNldFZhbHVlVHlwZToiaW50NjQifSxGPUdJO3ZhciBVST17RmxvYXQzMjoiZmxvYXQzMiIsRmxvYXQ2NDoiZmxvYXQ2NCIsU3BhY2VQcmVjaXNpb25UeXBlOiJmbG9hdDY0In0sVD1VSTtmdW5jdGlvbiBrSShBLGUpe2xldCB0PW51bGw7c3dpdGNoKEEpe2Nhc2UgRi5VSW50ODp7dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIEYuSW50ODp7dD1uZXcgSW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50MTY6e3Q9bmV3IFVpbnQxNkFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQxNjp7dD1uZXcgSW50MTZBcnJheShlKTticmVha31jYXNlIEYuVUludDMyOnt0PW5ldyBVaW50MzJBcnJheShlKTticmVha31jYXNlIEYuSW50MzI6e3Q9bmV3IEludDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnVWludDY0QXJyYXk9PSJmdW5jdGlvbiI/dD1uZXcgQmlnVWludDY0QXJyYXkoZSk6dD1uZXcgVWludDhBcnJheShlKTticmVha31jYXNlIEYuSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ0ludDY0QXJyYXk9PSJmdW5jdGlvbiI/dD1uZXcgQmlnSW50NjRBcnJheShlKTp0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgVC5GbG9hdDMyOnt0PW5ldyBGbG9hdDMyQXJyYXkoZSk7YnJlYWt9Y2FzZSBULkZsb2F0NjQ6e3Q9bmV3IEZsb2F0NjRBcnJheShlKTticmVha31jYXNlIm51bGwiOnt0PW51bGw7YnJlYWt9Y2FzZSBudWxsOnt0PW51bGw7YnJlYWt9ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoIlR5cGUgaXMgbm90IHN1cHBvcnRlZCBhcyBhIFR5cGVkQXJyYXkiKX1yZXR1cm4gdH12YXIgZD1rSTt2YXIgb3Q9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI9PSJmdW5jdGlvbiIsaXQ9bmV3IFRleHRFbmNvZGVyLGd0PW5ldyBUZXh0RGVjb2RlcigidXRmLTgiKTtmdW5jdGlvbiBIKEEsZSl7bGV0IHQ9e2ZsYWdzOiJyIixlbmNvZGluZzoiYmluYXJ5In0sST1BLmZzX29wZW4oZSx0LmZsYWdzKSxpPUEuZnNfc3RhdChlKS5zaXplLGc9bnVsbDtvdD9nPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcihpKTpnPW5ldyBBcnJheUJ1ZmZlcihpKTtsZXQgbj1uZXcgVWludDhBcnJheShnKTtyZXR1cm4gQS5mc19yZWFkKEksbiwwLGksMCksQS5mc19jbG9zZShJKSxufWZ1bmN0aW9uIG50KEEsZSx0KXtsZXQgST1udWxsO290P0k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKHQpOkk9bmV3IEFycmF5QnVmZmVyKHQpO2xldCByPW5ldyBVaW50OEFycmF5KEkpLGk9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLGUsdCk7cmV0dXJuIHIuc2V0KGkpLHJ9ZnVuY3Rpb24geShBLGUsdCxJKXtsZXQgcj0wO3JldHVybiBlIT09bnVsbCYmKHI9QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfYXJyYXlfYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxJLGUuYnVmZmVyLmJ5dGVMZW5ndGhdKSxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkoZS5idWZmZXIpLHIpKSxyfWZ1bmN0aW9uIFYoQSxlLHQpe2xldCBJPUpTT04uc3RyaW5naWZ5KGUpLHI9QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfanNvbl9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEkubGVuZ3RoXSk7QS53cml0ZUFzY2lpVG9NZW1vcnkoSSxyLCExKX1mdW5jdGlvbiBOKEEsZSx0LEkpe2xldCByPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLGUsdF0pLGk9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksZz1udChBLHIsaSk7cmV0dXJuIGQoSSxnLmJ1ZmZlcil9ZnVuY3Rpb24gb2UoQSxlKXtsZXQgdD1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfanNvbl9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciJdLFswLGVdKSxJPUEuQXNjaWlUb1N0cmluZyh0KTtyZXR1cm4gSlNPTi5wYXJzZShJKX1mdW5jdGlvbiBMSShBLGUsdCxJKXtJIT1udWxsJiZJLmxlbmd0aD4wJiZJLmZvckVhY2goZnVuY3Rpb24obyxCKXt2YXIgYztzd2l0Y2goby50eXBlKXtjYXNlIHUuVGV4dFN0cmVhbTp7bGV0IGE9aXQuZW5jb2RlKG8uZGF0YS5kYXRhKSxDPXkoQSxhLEIsMCksUT17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1YoQSxRLEIpO2JyZWFrfWNhc2UgdS5Kc29uQ29tcGF0aWJsZTp7bGV0IGE9aXQuZW5jb2RlKEpTT04uc3RyaW5naWZ5KG8uZGF0YSkpLEM9eShBLGEsQiwwKSxRPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07VihBLFEsQik7YnJlYWt9Y2FzZSB1LkJpbmFyeVN0cmVhbTp7bGV0IGE9by5kYXRhLmRhdGEsQz15KEEsYSxCLDApLFE9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTtWKEEsUSxCKTticmVha31jYXNlIHUuVGV4dEZpbGU6e0EuZnNfd3JpdGVGaWxlKG8uZGF0YS5wYXRoLG8uZGF0YS5kYXRhKTticmVha31jYXNlIHUuQmluYXJ5RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgdS5JbWFnZTp7bGV0IGE9by5kYXRhLEM9eShBLGEuZGF0YSxCLDApLFE9eShBLGEuZGlyZWN0aW9uLEIsMSksZj10eXBlb2YoKGM9YS5tZXRhZGF0YSk9PT1udWxsfHxjPT09dm9pZCAwP3ZvaWQgMDpjLmVudHJpZXMpPCJ1Ij9KU09OLnN0cmluZ2lmeShBcnJheS5mcm9tKGEubWV0YWRhdGEuZW50cmllcygpKSk6IltdIixtPXtpbWFnZVR5cGU6YS5pbWFnZVR5cGUsbmFtZTphLm5hbWUsb3JpZ2luOmEub3JpZ2luLHNwYWNpbmc6YS5zcGFjaW5nLGRpcmVjdGlvbjpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1F9YCxzaXplOmEuc2l6ZSxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLG1ldGFkYXRhOmZ9O1YoQSxtLEIpO2JyZWFrfWNhc2UgdS5NZXNoOntsZXQgYT1vLmRhdGEsQz15KEEsYS5wb2ludHMsQiwwKSxRPXkoQSxhLmNlbGxzLEIsMSksZj15KEEsYS5wb2ludERhdGEsQiwyKSxtPXkoQSxhLmNlbGxEYXRhLEIsMyksdz17bWVzaFR5cGU6YS5tZXNoVHlwZSxuYW1lOmEubmFtZSxudW1iZXJPZlBvaW50czphLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YCxudW1iZXJPZkNlbGxzOmEubnVtYmVyT2ZDZWxscyxjZWxsczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1F9YCxjZWxsQnVmZmVyU2l6ZTphLmNlbGxCdWZmZXJTaXplLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxudW1iZXJPZkNlbGxQaXhlbHM6YS5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttfWB9O1YoQSx3LEIpO2JyZWFrfWNhc2UgdS5Qb2x5RGF0YTp7bGV0IGE9by5kYXRhLEM9eShBLGEucG9pbnRzLEIsMCksUT15KEEsYS52ZXJ0aWNlcyxCLDEpLGY9eShBLGEubGluZXMsQiwyKSxtPXkoQSxhLnBvbHlnb25zLEIsMyksdz15KEEsYS50cmlhbmdsZVN0cmlwcyxCLDQpLE89eShBLGEucG9pbnREYXRhLEIsNSksSz15KEEsYS5wb2ludERhdGEsQiw2KSxKQT17cG9seURhdGFUeXBlOmEucG9seURhdGFUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLHZlcnRpY2VzQnVmZmVyU2l6ZTphLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke1F9YCxsaW5lc0J1ZmZlclNpemU6YS5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtmfWAscG9seWdvbnNCdWZmZXJTaXplOmEucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7bX1gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTphLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3d9YCxudW1iZXJPZlBvaW50UGl4ZWxzOmEubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtPfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7S31gfTtWKEEsSkEsQik7YnJlYWt9Y2FzZSBTLlRleHQ6e0EuZnNfd3JpdGVGaWxlKG8ucGF0aCxvLmRhdGEpO2JyZWFrfWNhc2UgUy5CaW5hcnk6e0EuZnNfd3JpdGVGaWxlKG8ucGF0aCxvLmRhdGEpO2JyZWFrfWNhc2UgUy5JbWFnZTp7bGV0IGE9by5kYXRhLEM9e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2RpcmVjdGlvbi5yYXciLHNpemU6YS5zaXplLGRhdGE6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGF0YS5yYXcifTtpZihBLmZzX21rZGlycyhgJHtvLnBhdGh9L2RhdGFgKSxBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLEpTT04uc3RyaW5naWZ5KEMpKSxhLmRhdGE9PT1udWxsKXRocm93IEVycm9yKCJpbWFnZS5kYXRhIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGEuZGF0YS5idWZmZXIpKSxBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvZGlyZWN0aW9uLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5kaXJlY3Rpb24uYnVmZmVyKSk7YnJlYWt9Y2FzZSBTLk1lc2g6e2xldCBhPW8uZGF0YSxDPXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50cy5yYXciLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9wb2ludERhdGEucmF3IixudW1iZXJPZkNlbGxzOmEubnVtYmVyT2ZDZWxscyxjZWxsczoiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9jZWxscy5yYXciLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9jZWxsRGF0YS5yYXciLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemV9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoQykpLEMubnVtYmVyT2ZQb2ludHM+MCl7aWYoYS5wb2ludHM9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLnBvaW50cyBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgLG5ldyBVaW50OEFycmF5KGEucG9pbnRzLmJ1ZmZlcikpfWlmKEMubnVtYmVyT2ZQb2ludFBpeGVscz4wKXtpZihhLnBvaW50RGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnREYXRhIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnREYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5wb2ludERhdGEuYnVmZmVyKSl9aWYoQy5udW1iZXJPZkNlbGxzPjApe2lmKGEuY2VsbHM9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLmNlbGxzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvY2VsbHMucmF3YCxuZXcgVWludDhBcnJheShhLmNlbGxzLmJ1ZmZlcikpfWlmKEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjApe2lmKGEuY2VsbERhdGE9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLmNlbGxEYXRhIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvY2VsbERhdGEucmF3YCxuZXcgVWludDhBcnJheShhLmNlbGxEYXRhLmJ1ZmZlcikpfWJyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIGlucHV0IEludGVyZmFjZVR5cGUiKX19KSxBLnJlc2V0TW9kdWxlU3Rkb3V0KCksQS5yZXNldE1vZHVsZVN0ZGVycigpO2xldCByPUEuc3RhY2tTYXZlKCksaT0wO3RyeXtpPUEuY2FsbE1haW4oZS5zbGljZSgpKX1jYXRjaChvKXt0aHJvdyB0eXBlb2Ygbz09Im51bWJlciImJihjb25zb2xlLmxvZygiRXhjZXB0aW9uIHdoaWxlIHJ1bm5pbmcgcGlwZWxpbmU6IiksY29uc29sZS5sb2coInN0ZG91dDoiLEEuZ2V0TW9kdWxlU3Rkb3V0KCkpLGNvbnNvbGUuZXJyb3IoInN0ZGVycjoiLEEuZ2V0TW9kdWxlU3RkZXJyKCkpLHR5cGVvZiBBLmdldEV4Y2VwdGlvbk1lc3NhZ2U8InUiP2NvbnNvbGUuZXJyb3IoImV4Y2VwdGlvbjoiLEEuZ2V0RXhjZXB0aW9uTWVzc2FnZShvKSk6Y29uc29sZS5lcnJvcigiQnVpbGQgbW9kdWxlIGluIERlYnVnIG1vZGUgZm9yIGV4Y2VwdGlvbiBtZXNzYWdlIGluZm9ybWF0aW9uLiIpKSxvfWZpbmFsbHl7QS5zdGFja1Jlc3RvcmUocil9bGV0IGc9QS5nZXRNb2R1bGVTdGRvdXQoKSxuPUEuZ2V0TW9kdWxlU3RkZXJyKCksRT1bXTtyZXR1cm4gdCE9bnVsbCYmdC5sZW5ndGg+MCYmaT09PTAmJnQuZm9yRWFjaChmdW5jdGlvbihvLEIpe2xldCBjPW51bGw7c3dpdGNoKG8udHlwZSl7Y2FzZSB1LlRleHRTdHJlYW06e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksZj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsQyxRKTtjPXtkYXRhOmd0LmRlY29kZShmKX07YnJlYWt9Y2FzZSB1Lkpzb25Db21wYXRpYmxlOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLGY9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEMsUSk7Yz1KU09OLnBhcnNlKGd0LmRlY29kZShmKSk7YnJlYWt9Y2FzZSB1LkJpbmFyeVN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKTtjPXtkYXRhOm50KEEsQyxRKX07YnJlYWt9Y2FzZSB1LlRleHRGaWxlOntjPXtwYXRoOm8uZGF0YS5wYXRoLGRhdGE6QS5mc19yZWFkRmlsZShvLmRhdGEucGF0aCx7ZW5jb2Rpbmc6InV0ZjgifSl9O2JyZWFrfWNhc2UgdS5CaW5hcnlGaWxlOntjPXtwYXRoOm8uZGF0YS5wYXRoLGRhdGE6SChBLG8uZGF0YS5wYXRoKX07YnJlYWt9Y2FzZSB1LkltYWdlOntsZXQgQz1vZShBLEIpO0MuZGF0YT1OKEEsQiwwLEMuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpLEMuZGlyZWN0aW9uPU4oQSxCLDEsVC5GbG9hdDY0KSxDLm1ldGFkYXRhPW5ldyBNYXAoQy5tZXRhZGF0YSksYz1DO2JyZWFrfWNhc2UgdS5NZXNoOntsZXQgQz1vZShBLEIpO0MubnVtYmVyT2ZQb2ludHM+MD9DLnBvaW50cz1OKEEsQiwwLEMubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTpDLnBvaW50cz1kKEMubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxzPjA/Qy5jZWxscz1OKEEsQiwxLEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUpOkMuY2VsbHM9ZChDLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZlBvaW50UGl4ZWxzPjA/Qy5wb2ludERhdGE9TihBLEIsMixDLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpDLnBvaW50RGF0YT1kKEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbFBpeGVscz4wP0MuY2VsbERhdGE9TihBLEIsMyxDLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkMuY2VsbERhdGE9ZChDLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxjPUM7YnJlYWt9Y2FzZSB1LlBvbHlEYXRhOntsZXQgQz1vZShBLEIpO0MubnVtYmVyT2ZQb2ludHM+MD9DLnBvaW50cz1OKEEsQiwwLFQuRmxvYXQzMik6Qy5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxDLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP0MudmVydGljZXM9TihBLEIsMSxGLlVJbnQzMik6Qy52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksQy5saW5lc0J1ZmZlclNpemU+MD9DLmxpbmVzPU4oQSxCLDIsRi5VSW50MzIpOkMubGluZXM9bmV3IFVpbnQzMkFycmF5LEMucG9seWdvbnNCdWZmZXJTaXplPjA/Qy5wb2x5Z29ucz1OKEEsQiwzLEYuVUludDMyKTpDLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxDLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP0MudHJpYW5nbGVTdHJpcHM9TihBLEIsNCxGLlVJbnQzMik6Qy50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksQy5udW1iZXJPZlBvaW50UGl4ZWxzPjA/Qy5wb2ludERhdGE9TihBLEIsNSxDLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5wb2ludERhdGE9ZChDLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1OKEEsQiw2LEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkMuY2VsbERhdGE9ZChDLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksYz1DO2JyZWFrfWNhc2UgUy5UZXh0OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Yz1BLmZzX3JlYWRGaWxlKG8ucGF0aCx7ZW5jb2Rpbmc6InV0ZjgifSk7YnJlYWt9Y2FzZSBTLkJpbmFyeTp7aWYodHlwZW9mIG8ucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO2M9SChBLG8ucGF0aCk7YnJlYWt9Y2FzZSBTLkltYWdlOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEM9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxRPUpTT04ucGFyc2UoQyksZj1IKEEsYCR7by5wYXRofS9kYXRhL2RhdGEucmF3YCk7US5kYXRhPWQoUS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSxmLmJ1ZmZlcik7bGV0IG09SChBLGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCk7US5kaXJlY3Rpb249ZChULkZsb2F0NjQsbS5idWZmZXIpLGM9UTticmVha31jYXNlIFMuTWVzaDp7aWYodHlwZW9mIG8ucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO2xldCBDPUEuZnNfcmVhZEZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCx7ZW5jb2Rpbmc6InV0ZjgifSksUT1KU09OLnBhcnNlKEMpO2lmKFEubnVtYmVyT2ZQb2ludHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9wb2ludHMucmF3YCk7US5wb2ludHM9ZChRLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxmLmJ1ZmZlcil9ZWxzZSBRLnBvaW50cz1kKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoUS5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2xldCBmPUgoQSxgJHtvLnBhdGh9L2RhdGEvcG9pbnREYXRhLnJhd2ApO1EucG9pbnREYXRhPWQoUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxmLmJ1ZmZlcil9ZWxzZSBRLnBvaW50RGF0YT1kKFEubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihRLm51bWJlck9mQ2VsbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgKTtRLmNlbGxzPWQoUS5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxmLmJ1ZmZlcil9ZWxzZSBRLmNlbGxzPWQoUS5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKFEubnVtYmVyT2ZDZWxsUGl4ZWxzPjApe2xldCBmPUgoQSxgJHtvLnBhdGh9L2RhdGEvY2VsbERhdGEucmF3YCk7US5jZWxsRGF0YT1kKFEubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxmLmJ1ZmZlcil9ZWxzZSBRLmNlbGxEYXRhPWQoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7Yz1RO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGE9e3R5cGU6by50eXBlLGRhdGE6Y307RS5wdXNoKGEpfSkse3JldHVyblZhbHVlOmksc3Rkb3V0Omcsc3RkZXJyOm4sb3V0cHV0czpFfX12YXIgej1MSTt2YXIgb0E9ZnVuY3Rpb24oQSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBvQT8odGhpcy52PUEsdGhpcyk6bmV3IG9BKEEpfSxPST1mdW5jdGlvbihBLGUsdCl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBJPXQuYXBwbHkoQSxlfHxbXSkscixpPVtdO3JldHVybiByPXt9LGcoIm5leHQiKSxnKCJ0aHJvdyIpLGcoInJldHVybiIpLHJbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHI7ZnVuY3Rpb24gZyhhKXtJW2FdJiYoclthXT1mdW5jdGlvbihDKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oUSxmKXtpLnB1c2goW2EsQyxRLGZdKT4xfHxuKGEsQyl9KX0pfWZ1bmN0aW9uIG4oYSxDKXt0cnl7RShJW2FdKEMpKX1jYXRjaChRKXtjKGlbMF1bM10sUSl9fWZ1bmN0aW9uIEUoYSl7YS52YWx1ZSBpbnN0YW5jZW9mIG9BP1Byb21pc2UucmVzb2x2ZShhLnZhbHVlLnYpLnRoZW4obyxCKTpjKGlbMF1bMl0sYSl9ZnVuY3Rpb24gbyhhKXtuKCJuZXh0IixhKX1mdW5jdGlvbiBCKGEpe24oInRocm93IixhKX1mdW5jdGlvbiBjKGEsQyl7YShDKSxpLnNoaWZ0KCksaS5sZW5ndGgmJm4oaVswXVswXSxpWzBdWzFdKX19LEpJPWZ1bmN0aW9uKEEpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgZT1BW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSx0O3JldHVybiBlP2UuY2FsbChBKTooQT10eXBlb2YgX192YWx1ZXM9PSJmdW5jdGlvbiI/X192YWx1ZXMoQSk6QVtTeW1ib2wuaXRlcmF0b3JdKCksdD17fSxJKCJuZXh0IiksSSgidGhyb3ciKSxJKCJyZXR1cm4iKSx0W1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0KTtmdW5jdGlvbiBJKGkpe3RbaV09QVtpXSYmZnVuY3Rpb24oZyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4sRSl7Zz1BW2ldKGcpLHIobixFLGcuZG9uZSxnLnZhbHVlKX0pfX1mdW5jdGlvbiByKGksZyxuLEUpe1Byb21pc2UucmVzb2x2ZShFKS50aGVuKGZ1bmN0aW9uKG8pe2koe3ZhbHVlOm8sZG9uZTpufSl9LGcpfX07ZnVuY3Rpb24gTUkoQSl7cmV0dXJuIE9JKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKigpe2ZvcihsZXQgdD0wO3Q8TEEubGVuZ3RoO3QrKyl7bGV0IEk9TEFbdF0rIi1yZWFkLWltYWdlIixyPXlpZWxkIG9BKEcoSSxBLmNvbmZpZy5pbWFnZUlPVXJsKSk7eWllbGQgeWllbGQgb0Eocil9fSl9YXN5bmMgZnVuY3Rpb24gYkkoQSxlKXt2YXIgdCxJO2lmKEEubWltZVR5cGUmJmllLmhhcyhBLm1pbWVUeXBlKSl7bGV0IG49aWUuZ2V0KEEubWltZVR5cGUpK2U7cmV0dXJuIGF3YWl0IEcobixBLmNvbmZpZy5pbWFnZUlPVXJsKX1sZXQgcj1rQShBLmZpbGVOYW1lKTtpZihnZS5oYXMocikpe2xldCBuPWdlLmdldChyKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcuaW1hZ2VJT1VybCl9Zm9yKGxldCBuPTA7bjxMQS5sZW5ndGg7KytuKXtsZXQgRT0wO3RyeXtmb3IodmFyIGk9KHQ9dm9pZCAwLEpJKE1JKEEpKSksZztnPWF3YWl0IGkubmV4dCgpLCFnLmRvbmU7KXtsZXQgbz1nLnZhbHVlO3RyeXtsZXR7cmV0dXJuVmFsdWU6QixvdXRwdXRzOmN9PWF3YWl0IHoobyxBLmFyZ3MsQS5vdXRwdXRzLEEuaW5wdXRzKTtpZihCPT09MClyZXR1cm4gb31jYXRjaHt9RSsrfX1jYXRjaChvKXt0PXtlcnJvcjpvfX1maW5hbGx5e3RyeXtnJiYhZy5kb25lJiYoST1pLnJldHVybikmJmF3YWl0IEkuY2FsbChpKX1maW5hbGx5e2lmKHQpdGhyb3cgdC5lcnJvcn19fXRocm93IEVycm9yKGBDb3VsZCBub3QgZmluZCBJTyBmb3I6ICR7QS5maWxlTmFtZX1gKX12YXIgbmU9Ykk7dmFyIEhJPW5ldyBNYXAoW10pLGFlPUhJO3ZhciBZST1uZXcgTWFwKFtbInZ0ayIsIlZUS1BvbHlEYXRhTWVzaElPIl0sWyJWVEsiLCJWVEtQb2x5RGF0YU1lc2hJTyJdLFsiYnl1IiwiQllVTWVzaElPIl0sWyJCWVUiLCJCWVVNZXNoSU8iXSxbImZzYSIsIkZyZWVTdXJmZXJBc2NpaU1lc2hJTyJdLFsiRlNBIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIl0sWyJmc2IiLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIl0sWyJGU0IiLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIl0sWyJvYmoiLCJPQkpNZXNoSU8iXSxbIk9CSiIsIk9CSk1lc2hJTyJdLFsib2ZmIiwiT0ZGTWVzaElPIl0sWyJPRkYiLCJPRkZNZXNoSU8iXSxbInN0bCIsIlNUTE1lc2hJTyJdLFsiU1RMIiwiU1RMTWVzaElPIl0sWyJzd2MiLCJTV0NNZXNoSU8iXSxbIlNXQyIsIlNXQ01lc2hJTyJdLFsiaXdtIiwiV2FzbU1lc2hJTyJdLFsiaXdtLmNib3IiLCJXYXNtTWVzaElPIl0sWyJpd20uY2Jvci56c3QiLCJXYXNtWnN0ZE1lc2hJTyJdXSksc2U9WUk7dmFyIHFJPVsiQllVTWVzaElPIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIiwiRnJlZVN1cmZlckJpbmFyeU1lc2hJTyIsIk9CSk1lc2hJTyIsIk9GRk1lc2hJTyIsIlNUTE1lc2hJTyIsIlNXQ01lc2hJTyIsIlZUS1BvbHlEYXRhTWVzaElPIiwiV2FzbU1lc2hJTyIsIldhc21ac3RkTWVzaElPIl0sT0E9cUk7dmFyIG5BPWZ1bmN0aW9uKEEpe3JldHVybiB0aGlzIGluc3RhbmNlb2YgbkE/KHRoaXMudj1BLHRoaXMpOm5ldyBuQShBKX0sVEk9ZnVuY3Rpb24oQSxlLHQpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgST10LmFwcGx5KEEsZXx8W10pLHIsaT1bXTtyZXR1cm4gcj17fSxnKCJuZXh0IiksZygidGhyb3ciKSxnKCJyZXR1cm4iKSxyW1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSxyO2Z1bmN0aW9uIGcoYSl7SVthXSYmKHJbYV09ZnVuY3Rpb24oQyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKFEsZil7aS5wdXNoKFthLEMsUSxmXSk+MXx8bihhLEMpfSl9KX1mdW5jdGlvbiBuKGEsQyl7dHJ5e0UoSVthXShDKSl9Y2F0Y2goUSl7YyhpWzBdWzNdLFEpfX1mdW5jdGlvbiBFKGEpe2EudmFsdWUgaW5zdGFuY2VvZiBuQT9Qcm9taXNlLnJlc29sdmUoYS52YWx1ZS52KS50aGVuKG8sQik6YyhpWzBdWzJdLGEpfWZ1bmN0aW9uIG8oYSl7bigibmV4dCIsYSl9ZnVuY3Rpb24gQihhKXtuKCJ0aHJvdyIsYSl9ZnVuY3Rpb24gYyhhLEMpe2EoQyksaS5zaGlmdCgpLGkubGVuZ3RoJiZuKGlbMF1bMF0saVswXVsxXSl9fSxLST1mdW5jdGlvbihBKXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIGU9QVtTeW1ib2wuYXN5bmNJdGVyYXRvcl0sdDtyZXR1cm4gZT9lLmNhbGwoQSk6KEE9dHlwZW9mIF9fdmFsdWVzPT0iZnVuY3Rpb24iP19fdmFsdWVzKEEpOkFbU3ltYm9sLml0ZXJhdG9yXSgpLHQ9e30sSSgibmV4dCIpLEkoInRocm93IiksSSgicmV0dXJuIiksdFtTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30sdCk7ZnVuY3Rpb24gSShpKXt0W2ldPUFbaV0mJmZ1bmN0aW9uKGcpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihuLEUpe2c9QVtpXShnKSxyKG4sRSxnLmRvbmUsZy52YWx1ZSl9KX19ZnVuY3Rpb24gcihpLGcsbixFKXtQcm9taXNlLnJlc29sdmUoRSkudGhlbihmdW5jdGlvbihvKXtpKHt2YWx1ZTpvLGRvbmU6bn0pfSxnKX19O2Z1bmN0aW9uIHhJKEEpe3JldHVybiBUSSh0aGlzLGFyZ3VtZW50cyxmdW5jdGlvbiooKXtmb3IobGV0IHQ9MDt0PE9BLmxlbmd0aDt0Kyspe2xldCBJPU9BW3RdKyItcmVhZC1tZXNoIixyPXlpZWxkIG5BKEcoSSxBLmNvbmZpZy5tZXNoSU9VcmwpKTt5aWVsZCB5aWVsZCBuQShyKX19KX1hc3luYyBmdW5jdGlvbiBQSShBLGUpe3ZhciB0LEk7aWYoQS5taW1lVHlwZSYmYWUuaGFzKEEubWltZVR5cGUpKXtsZXQgbj1hZS5nZXQoQS5taW1lVHlwZSkrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLm1lc2hJT1VybCl9bGV0IHI9a0EoQS5maWxlTmFtZSk7aWYoc2UuaGFzKHIpKXtsZXQgbj1zZS5nZXQocikrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLm1lc2hJT1VybCl9Zm9yKGxldCBuPTA7bjxPQS5sZW5ndGg7KytuKXtsZXQgRT0wO3RyeXtmb3IodmFyIGk9KHQ9dm9pZCAwLEtJKHhJKEEpKSksZztnPWF3YWl0IGkubmV4dCgpLCFnLmRvbmU7KXtsZXQgbz1nLnZhbHVlO3RyeXtsZXR7cmV0dXJuVmFsdWU6QixvdXRwdXRzOmN9PWF3YWl0IHoobyxBLmFyZ3MsQS5vdXRwdXRzLEEuaW5wdXRzKTtpZihCPT09MClyZXR1cm4gb31jYXRjaHt9RSsrfX1jYXRjaChvKXt0PXtlcnJvcjpvfX1maW5hbGx5e3RyeXtnJiYhZy5kb25lJiYoST1pLnJldHVybikmJmF3YWl0IEkuY2FsbChpKX1maW5hbGx5e2lmKHQpdGhyb3cgdC5lcnJvcn19fXRocm93IEVycm9yKGBDb3VsZCBub3QgZmluZCBJTyBmb3I6ICR7QS5maWxlTmFtZX1gKX12YXIgQ2U9UEk7dmFyIFdJPXR5cGVvZiBnbG9iYWxUaGlzLlNoYXJlZEFycmF5QnVmZmVyPCJ1IjtmdW5jdGlvbiBqSShBKXtpZihBPT1udWxsKXJldHVybltdO2xldCBlPVtdO2ZvcihsZXQgdD0wO3Q8QS5sZW5ndGg7dCsrKXtsZXQgST1aSShBW3RdKTtJIT09bnVsbCYmZS5wdXNoKEkpfXJldHVybiBlfWZ1bmN0aW9uIFpJKEEpe2lmKEE9PW51bGwpcmV0dXJuIG51bGw7bGV0IGU9bnVsbDtyZXR1cm4gQS5idWZmZXIhPT12b2lkIDA/ZT1BLmJ1ZmZlcjpBLmJ5dGVMZW5ndGghPT12b2lkIDAmJihlPUEpLFdJJiZlIGluc3RhbmNlb2YgU2hhcmVkQXJyYXlCdWZmZXI/bnVsbDplfXZhciBhdD1qSTtmdW5jdGlvbiBfSShBKXtyZXR1cm5bQS5kYXRhLEEuZGlyZWN0aW9uXX12YXIgQmU9X0k7ZnVuY3Rpb24gVkkoQSl7cmV0dXJuW0EucG9pbnRzLEEucG9pbnREYXRhLEEuY2VsbHMsQS5jZWxsRGF0YV19dmFyIFFlPVZJO2Z1bmN0aW9uIHpJKEEpe3JldHVybltBLnBvaW50cyxBLnZlcnRpY2VzLEEubGluZXMsQS5wb2x5Z29ucyxBLnRyaWFuZ2xlU3RyaXBzLEEucG9pbnREYXRhLEEuY2VsbERhdGFdfXZhciBzdD16STthc3luYyBmdW5jdGlvbiBYSShBLGUsdCxJKXtsZXQgcj16KEEsZSx0LEkpLGk9W107cmV0dXJuIHIub3V0cHV0cyYmci5vdXRwdXRzLmZvckVhY2goZnVuY3Rpb24oZyl7aWYoZy50eXBlPT09dS5CaW5hcnlTdHJlYW18fGcudHlwZT09PXUuQmluYXJ5RmlsZSl7bGV0IG49Zy5kYXRhO2kucHVzaChuKX1lbHNlIGlmKGcudHlwZT09PXUuSW1hZ2Upe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uQmUobikpfWVsc2UgaWYoZy50eXBlPT09dS5NZXNoKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLlFlKG4pKX1lbHNlIGlmKGcudHlwZT09PXUuUG9seURhdGEpe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uc3QobikpfWVsc2UgaWYoZy50eXBlPT09Uy5CaW5hcnkpe2xldCBuPWcuZGF0YTtpLnB1c2gobil9ZWxzZSBpZihnLnR5cGU9PT1TLkltYWdlKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLkJlKG4pKX1lbHNlIGlmKGcudHlwZT09PVMuTWVzaCl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5RZShuKSl9fSksSEEocixhdChpKSl9dmFyIFk9WEk7dmFyIHZJPXttZXNoVG9Qb2x5RGF0YTphc3luYyBmdW5jdGlvbihBLGUsdCxJKXtsZXQgcj1hd2FpdCBHKCJtZXNoLXRvLXBvbHlkYXRhIixBLm1lc2hJT1VybCk7cmV0dXJuIFkocixlLHQsSSl9LHBvbHlEYXRhVG9NZXNoOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkpe2xldCByPWF3YWl0IEcoInBvbHlkYXRhLXRvLW1lc2giLEEubWVzaElPVXJsKTtyZXR1cm4gWShyLGUsdCxJKX0scmVhZEltYWdlOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz1hd2FpdCBuZSh7ZmlsZU5hbWU6dCxtaW1lVHlwZTplLGNvbmZpZzpBLGFyZ3M6SSxvdXRwdXRzOnIsaW5wdXRzOml9LCItcmVhZC1pbWFnZSIpO3JldHVybiBZKGcsSSxyLGkpfSx3cml0ZUltYWdlOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz1hd2FpdCBuZSh7ZmlsZU5hbWU6dCxtaW1lVHlwZTplLGNvbmZpZzpBLGFyZ3M6SSxvdXRwdXRzOnIsaW5wdXRzOml9LCItd3JpdGUtaW1hZ2UiKTtyZXR1cm4gWShnLEkscixpKX0scmVhZE1lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IENlKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi1yZWFkLW1lc2giKTtyZXR1cm4gWShnLEkscixpKX0sd3JpdGVNZXNoOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz1hd2FpdCBDZSh7ZmlsZU5hbWU6dCxtaW1lVHlwZTplLGNvbmZpZzpBLGFyZ3M6SSxvdXRwdXRzOnIsaW5wdXRzOml9LCItd3JpdGUtbWVzaCIpO3JldHVybiBZKGcsSSxyLGkpfSxydW5QaXBlbGluZTphc3luYyBmdW5jdGlvbihBLGUsdCxJLHIsaSl7bGV0IGc9dHlwZW9mIEFbdF0+InUiP3Q6QVt0XSxuPWF3YWl0IEcoZSxnKTtyZXR1cm4gWShuLEkscixpKX19O0VBKHZJKTslMEEvKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOiUwQSUwQWNvbWxpbmsvZGlzdC9lc20vY29tbGluay5tanM6JTBBICAoKiolMEEgICAqIEBsaWNlbnNlJTBBICAgKiBDb3B5cmlnaHQgMjAxOSBHb29nbGUgTExDJTBBICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMCUwQSAgICopJTBBKi8lMEEnO0V0KGR0KTtleHBvcnR7b2UgYXMgY29tcGFyZURvdWJsZUltYWdlcyxvbiBhcyBjb21wYXJlSW1hZ2VzLFF0IGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLGJBIGFzIGdldFBpcGVsaW5lc0Jhc2VVcmwsRXQgYXMgc2V0UGlwZWxpbmVXb3JrZXJVcmwsZ3MgYXMgc2V0UGlwZWxpbmVzQmFzZVVybH07Ci8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246Cgpjb21saW5rL2Rpc3QvZXNtL2NvbWxpbmsubWpzOgogICgqKgogICAqIEBsaWNlbnNlCiAgICogQ29weXJpZ2h0IDIwMTkgR29vZ2xlIExMQwogICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wCiAgICopCiovCg==""" +default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml b/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml index 792111b3c..bedd106b4 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] keywords = [ "itkwasm", diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/test/fixtures.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/test/fixtures.py index 42ca4943d..27af09d50 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/test/fixtures.py +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/test/fixtures.py @@ -25,7 +25,6 @@ def input_data(): ] data = {} for f in test_files: - path = str(input_base_path / f) + '.pickle' - with open(path, 'rb') as fp: - data[str(f.name)] = pickle.load(fp) + with open(input_base_path / f, 'rb') as fp: + data[str(f.name)] = fp.read() return data \ No newline at end of file diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_compare_images_async.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_compare_images_async.py index 9defcb277..77ab4fe9f 100644 --- a/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_compare_images_async.py +++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_compare_images_async.py @@ -9,18 +9,25 @@ @run_in_pyodide(packages=['micropip', 'numpy']) async def test_compare_double_images_async(selenium, package_wheel, input_data): import micropip - await micropip.install(package_wheel, 'numpy', 'itkwasm') + await micropip.install(package_wheel) + await micropip.install('itkwasm-image-io-emscripten') + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) - from itkwasm_compare_images_emscripten import compare_double_images_async import numpy as np from itkwasm import Image from itkwasm.pyodide import to_js as itkwasm_to_js + from itkwasm_compare_images_emscripten import compare_double_images_async + from itkwasm_image_io_emscripten import imread_async test_image_file = 'cake_easy.iwi.cbor' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'cake_hard.iwi.cbor' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_double_images_async(test_image, baseline_images=[baseline_image]) @@ -37,18 +44,25 @@ async def test_compare_double_images_async(selenium, package_wheel, input_data): @run_in_pyodide(packages=['micropip', 'numpy']) async def test_compare_images_async(selenium, package_wheel, input_data): import micropip - await micropip.install(package_wheel, 'numpy', 'itkwasm') + await micropip.install(package_wheel) + await micropip.install('itkwasm-image-io-emscripten') + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) from itkwasm_compare_images_emscripten import compare_images_async + from itkwasm_image_io_emscripten import imread_async import numpy as np from itkwasm import Image from itkwasm.pyodide import to_js as itkwasm_to_js test_image_file = 'cake_easy.iwi.cbor' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'cake_hard.iwi.cbor' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image]) @@ -63,10 +77,12 @@ async def test_compare_images_async(selenium, package_wheel, input_data): assert difference_image_rendering.imageType.componentType == 'uint8' test_image_file = 'cake_easy.png' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'cake_hard.png' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image]) @@ -81,10 +97,12 @@ async def test_compare_images_async(selenium, package_wheel, input_data): assert difference_image_rendering.imageType.componentType == 'uint8' test_image_file = 'apple.jpg' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'orange.jpg' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image]) @@ -92,8 +110,8 @@ async def test_compare_images_async(selenium, package_wheel, input_data): assert metrics['numberOfPixelsWithDifferences'] == 26477 assert metrics['minimumDifference'] == 0.002273026683894841 assert metrics['maximumDifference'] == 312.2511648746159 - assert metrics['totalDifference'] == 3121656.100202402 - assert metrics['meanDifference'] == 117.90067228924735 + assert metrics['totalDifference'] == 3121703.1639738297 + assert metrics['meanDifference'] == 117.90244982338746 assert difference_image.imageType.componentType == 'float64' assert difference_image_rendering.imageType.componentType == 'uint8' diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py index 055276878..ce1305bf4 100644 --- a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py +++ b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py @@ -1 +1 @@ -__version__ = "3.0.1" +__version__ = "4.0.0" diff --git a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py index 055276878..ce1305bf4 100644 --- a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py +++ b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py @@ -1 +1 @@ -__version__ = "3.0.1" +__version__ = "4.0.0" diff --git a/packages/compare-images/python/itkwasm-compare-images/test/fixtures.py b/packages/compare-images/python/itkwasm-compare-images/test/fixtures.py index deef3d21f..9ae4c2e7f 100644 --- a/packages/compare-images/python/itkwasm-compare-images/test/fixtures.py +++ b/packages/compare-images/python/itkwasm-compare-images/test/fixtures.py @@ -25,7 +25,6 @@ def input_data(): ] data = {} for f in test_files: - path = str(input_base_path / f) + '.pickle' - with open(path, 'rb') as fp: - data[str(f.name)] = pickle.load(fp) + with open(input_base_path / f, 'rb') as fp: + data[str(f.name)] = fp.read() return data diff --git a/packages/compare-images/python/itkwasm-compare-images/test/test_compare_images_async.py b/packages/compare-images/python/itkwasm-compare-images/test/test_compare_images_async.py index 28256b2e4..4a6315550 100644 --- a/packages/compare-images/python/itkwasm-compare-images/test/test_compare_images_async.py +++ b/packages/compare-images/python/itkwasm-compare-images/test/test_compare_images_async.py @@ -9,18 +9,25 @@ @run_in_pyodide(packages=['micropip', 'numpy']) async def test_compare_double_images_async(selenium, package_wheel, input_data): import micropip - await micropip.install(package_wheel, 'numpy', 'itkwasm') + await micropip.install(package_wheel) + await micropip.install('itkwasm-image-io-emscripten') + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) from itkwasm_compare_images import compare_double_images_async import numpy as np from itkwasm import Image from itkwasm.pyodide import to_js as itkwasm_to_js + from itkwasm_image_io_emscripten import imread_async test_image_file = 'cake_easy.iwi.cbor' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'cake_hard.iwi.cbor' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_double_images_async(test_image, baseline_images=[baseline_image]) @@ -37,18 +44,25 @@ async def test_compare_double_images_async(selenium, package_wheel, input_data): @run_in_pyodide(packages=['micropip', 'numpy']) async def test_compare_images_async(selenium, package_wheel, input_data): import micropip - await micropip.install(package_wheel, 'numpy', 'itkwasm') + await micropip.install(package_wheel) + await micropip.install('itkwasm-image-io-emscripten') + def write_input_data_to_fs(input_data, filename): + with open(filename, 'wb') as fp: + fp.write(input_data[filename]) from itkwasm_compare_images import compare_images_async import numpy as np from itkwasm import Image from itkwasm.pyodide import to_js as itkwasm_to_js + from itkwasm_image_io_emscripten import imread_async test_image_file = 'cake_easy.iwi.cbor' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'cake_hard.iwi.cbor' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image]) @@ -63,10 +77,12 @@ async def test_compare_images_async(selenium, package_wheel, input_data): assert difference_image_rendering.imageType.componentType == 'uint8' test_image_file = 'cake_easy.png' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'cake_hard.png' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image]) @@ -81,10 +97,12 @@ async def test_compare_images_async(selenium, package_wheel, input_data): assert difference_image_rendering.imageType.componentType == 'uint8' test_image_file = 'apple.jpg' - test_image = Image(**input_data[test_image_file]) + write_input_data_to_fs(input_data, test_image_file) + test_image = await imread_async(test_image_file) baseline_image_file = 'orange.jpg' - baseline_image = Image(**input_data[baseline_image_file]) + write_input_data_to_fs(input_data, baseline_image_file) + baseline_image = await imread_async(baseline_image_file) metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image]) @@ -92,8 +110,8 @@ async def test_compare_images_async(selenium, package_wheel, input_data): assert metrics['numberOfPixelsWithDifferences'] == 26477 assert metrics['minimumDifference'] == 0.002273026683894841 assert metrics['maximumDifference'] == 312.2511648746159 - assert metrics['totalDifference'] == 3121656.100202402 - assert metrics['meanDifference'] == 117.90067228924735 + assert metrics['totalDifference'] == 3121703.1639738297 + assert metrics['meanDifference'] == 117.90244982338746 assert difference_image.imageType.componentType == 'float64' assert difference_image_rendering.imageType.componentType == 'uint8' diff --git a/packages/compare-images/typescript/build/rollup.browser.config.js b/packages/compare-images/typescript/build/rollup.browser.config.js deleted file mode 100644 index 98ec279b6..000000000 --- a/packages/compare-images/typescript/build/rollup.browser.config.js +++ /dev/null @@ -1,49 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import nodePolyfills from 'rollup-plugin-polyfill-node' -import ignore from 'rollup-plugin-ignore' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import json from '@rollup/plugin-json' -import path from 'path' -import OMT from "@surma/rollup-plugin-off-main-thread" - -const omtCustom = OMT() -omtCustom.resolveImportMeta = () => { - return 'import.meta.url' -} - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index.ts', - output: [ - { - dir: `./dist`, - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - onwarn: function onwarn(warning, warn) { - if (warning.code === 'THIS_IS_UNDEFINED') return; - if (warning.message.includes('Very few browsers support ES modules in Workers.')) return; - console.log('onwarn', warning) - warn(warning); - }, - plugins: [ - ignore(['crypto']), - nodeResolve({ - preferBuiltins: false, - browser: true, - }), - commonjs({ - transformMixedEsModules: true - }), - nodePolyfills(), - typescript(), - json(), - omtCustom, - ] -} diff --git a/packages/compare-images/typescript/build/rollup.node.config.js b/packages/compare-images/typescript/build/rollup.node.config.js deleted file mode 100644 index 57d19955d..000000000 --- a/packages/compare-images/typescript/build/rollup.node.config.js +++ /dev/null @@ -1,36 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import path from 'path' - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index-node.ts', - output: [ - { - dir: './dist', - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - onwarn: function onwarn(warning, warn) { - if (warning.code === 'THIS_IS_UNDEFINED') return; - warn(warning); - }, - plugins: [ - commonjs({ - transformMixedEsModules: true - }), - nodeResolve({ - preferBuiltins: true, - browser: false, - }), - typescript(), - json(), - ], -} diff --git a/packages/compare-images/typescript/build/vite.config.js b/packages/compare-images/typescript/build/vite.config.js index adf8b9cce..5266d1417 100644 --- a/packages/compare-images/typescript/build/vite.config.js +++ b/packages/compare-images/typescript/build/vite.config.js @@ -12,7 +12,7 @@ export default defineConfig({ format: 'es' }, optimizeDeps: { - exclude: ['@itk-wasm/image-io'] + exclude: ['itk-wasm', '@itk-wasm/image-io'] }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory diff --git a/packages/compare-images/typescript/package.json b/packages/compare-images/typescript/package.json index 4a4e34f9f..440e98ce5 100644 --- a/packages/compare-images/typescript/package.json +++ b/packages/compare-images/typescript/package.json @@ -1,13 +1,13 @@ { "name": "@itk-wasm/compare-images", - "version": "3.0.1", + "version": "4.0.0", "description": "Compare images with a tolerance for regression testing.", "type": "module", "module": "./dist/index.js", - "types": "./dist/src/index.d.ts", + "types": "./dist/index.d.ts", "exports": { ".": { - "types": "./dist/src/index.d.ts", + "types": "./dist/index.d.ts", "browser": "./dist/index.js", "node": "./dist/index-node.js", "default": "./dist/index.js" @@ -24,9 +24,9 @@ "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", - "build:node": "rollup -c ./build/rollup.node.config.js", - "build:browser": "rollup -c ./build/rollup.browser.config.js", + "build": "npm run build:tsc && npm run build:browser:workerEmbedded && npm run build:browser:workerEmbeddedMin && npm run build:demo", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build:browser:workerEmbeddedMin": "esbuild --minify --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.min.js ./src/index-worker-embedded.min.ts", "build:tsc": "tsc --pretty", "copyShoelaceAssets": "shx mkdir -p test/browser/demo-app/public && shx cp -r node_modules/@shoelace-style/shoelace/dist/assets test/browser/demo-app/public/", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" @@ -40,27 +40,16 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.149" + "itk-wasm": "^1.0.0-b.154" }, "devDependencies": { - "@itk-wasm/image-io": "^0.3.0", - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.0", - "@rollup/plugin-typescript": "^11.1.1", + "@itk-wasm/image-io": "^0.4.0", "@shoelace-style/shoelace": "^2.5.2", - "@surma/rollup-plugin-off-main-thread": "^2.2.3", "@types/node": "^20.2.5", "ava": "^5.3.1", "cypress": "^12.17.2", - "debug": "^4.3.4", - "rollup": "^3.9.0", - "rollup-plugin-ignore": "^1.0.10", - "rollup-plugin-polyfill-node": "^0.12.0", "shx": "^0.3.4", - "supports-color": "^9.3.1", - "tslib": "^2.5.2", + "start-server-and-test": "^2.0.2", "typescript": "^5.0.4", "vite": "^4.4.11", "vite-plugin-static-copy": "^0.17.0" @@ -69,4 +58,4 @@ "type": "git", "url": "https://github.com/InsightSoftwareConsortium/itk-wasm" } -} \ No newline at end of file +} diff --git a/packages/compare-images/typescript/pnpm-lock.yaml b/packages/compare-images/typescript/pnpm-lock.yaml new file mode 100644 index 000000000..4130e0e76 --- /dev/null +++ b/packages/compare-images/typescript/pnpm-lock.yaml @@ -0,0 +1,2765 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +dependencies: + itk-wasm: + specifier: ^1.0.0-b.154 + version: 1.0.0-b.154 + +devDependencies: + '@itk-wasm/image-io': + specifier: ^0.4.0 + version: 0.4.0 + '@shoelace-style/shoelace': + specifier: ^2.5.2 + version: 2.11.2(@types/react@18.2.37) + '@types/node': + specifier: ^20.2.5 + version: 20.9.0 + ava: + specifier: ^5.3.1 + version: 5.3.1 + cypress: + specifier: ^12.17.2 + version: 12.17.4 + shx: + specifier: ^0.3.4 + version: 0.3.4 + start-server-and-test: + specifier: ^2.0.2 + version: 2.0.2 + typescript: + specifier: ^5.0.4 + version: 5.2.2 + vite: + specifier: ^4.4.11 + version: 4.5.0(@types/node@20.9.0) + vite-plugin-static-copy: + specifier: ^0.17.0 + version: 0.17.0(vite@4.5.0) + +packages: + + /@babel/runtime@7.23.2: + resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.0 + + /@colors/colors@1.5.0: + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + requiresBuild: true + dev: true + optional: true + + /@ctrl/tinycolor@4.0.2: + resolution: {integrity: sha512-fKQinXE9pJ83J1n+C3rDl2xNLJwfoYNvXLRy5cYZA9hBJJw2q+sbb/AOSNKmLxnTWyNTmy4994dueSwP4opi5g==} + engines: {node: '>=14'} + dev: true + + /@cypress/request@2.88.12: + resolution: {integrity: sha512-tOn+0mDZxASFM+cuAP9szGUGPI1HwWVSvdzm7V4cCsPdFTx6qMj29CwaQmRAMIEhORIUBFBsYROYJcveK4uOjA==} + engines: {node: '>= 6'} + dependencies: + aws-sign2: 0.7.0 + aws4: 1.12.0 + caseless: 0.12.0 + combined-stream: 1.0.8 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + http-signature: 1.3.6 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.35 + performance-now: 2.1.0 + qs: 6.10.4 + safe-buffer: 5.2.1 + tough-cookie: 4.1.3 + tunnel-agent: 0.6.0 + uuid: 8.3.2 + dev: true + + /@cypress/xvfb@1.2.4(supports-color@8.1.1): + resolution: {integrity: sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==} + dependencies: + debug: 3.2.7(supports-color@8.1.1) + lodash.once: 4.1.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@floating-ui/core@1.5.0: + resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} + dependencies: + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/dom@1.5.3: + resolution: {integrity: sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==} + dependencies: + '@floating-ui/core': 1.5.0 + '@floating-ui/utils': 0.1.6 + dev: true + + /@floating-ui/utils@0.1.6: + resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} + dev: true + + /@hapi/hoek@9.3.0: + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + dev: true + + /@hapi/topo@5.1.0: + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@itk-wasm/image-io@0.4.0: + resolution: {integrity: sha512-2bZdKCRIvWE+sQXJFjzjwgMQZnrqKqzy+yecee6/9IblqhBu76bcs5tdjcAwlC05LmK4HtntC3BwOLLwcA1KpQ==} + dependencies: + itk-wasm: 1.0.0-b.154 + transitivePeerDependencies: + - debug + dev: true + + /@lit-labs/ssr-dom-shim@1.1.2: + resolution: {integrity: sha512-jnOD+/+dSrfTWYfSXBXlo5l5f0q1UuJo3tkbMDCYA2lKUYq79jaxqtGEvnRoh049nt1vdo1+45RinipU6FGY2g==} + dev: true + + /@lit/react@1.0.1(@types/react@18.2.37): + resolution: {integrity: sha512-io4yIAl9ZFY5coI2ix+nSly4rmEKLFyZM66mxOr9xvxDqwtjdVU/g6Tchb7bo+A23+5Uu/1RZpLCpvHLCGi0rw==} + peerDependencies: + '@types/react': 17 || 18 + dependencies: + '@types/react': 18.2.37 + dev: true + + /@lit/reactive-element@2.0.1: + resolution: {integrity: sha512-eu50SQXHRthFwWJMp0oAFg95Rvm6MTPjxSXWuvAu7It90WVFLFpNBoIno7XOXSDvVgTrtKnUV4OLJqys2Svn4g==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.1.2 + dev: true + + /@nodelib/fs.scandir@2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + dev: true + + /@nodelib/fs.stat@2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + dev: true + + /@nodelib/fs.walk@1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.15.0 + dev: true + + /@shoelace-style/animations@1.1.0: + resolution: {integrity: sha512-Be+cahtZyI2dPKRm8EZSx3YJQ+jLvEcn3xzRP7tM4tqBnvd/eW/64Xh0iOf0t2w5P8iJKfdBbpVNE9naCaOf2g==} + dev: true + + /@shoelace-style/localize@3.1.2: + resolution: {integrity: sha512-Hf45HeO+vdQblabpyZOTxJ4ZeZsmIUYXXPmoYrrR4OJ5OKxL+bhMz5mK8JXgl7HsoEowfz7+e248UGi861de9Q==} + dev: true + + /@shoelace-style/shoelace@2.11.2(@types/react@18.2.37): + resolution: {integrity: sha512-V94PTZ3CKcRH7NozDIEK5gMG3yeCZhF/3jCpKZ7Wexpf9kOqIRaMGoW3omq21I8NRefNLEknkV9Q392JIZLjBA==} + engines: {node: '>=14.17.0'} + dependencies: + '@ctrl/tinycolor': 4.0.2 + '@floating-ui/dom': 1.5.3 + '@lit/react': 1.0.1(@types/react@18.2.37) + '@shoelace-style/animations': 1.1.0 + '@shoelace-style/localize': 3.1.2 + composed-offset-position: 0.0.4 + lit: 3.0.2 + qr-creator: 1.0.0 + transitivePeerDependencies: + - '@types/react' + dev: true + + /@sideway/address@4.1.4: + resolution: {integrity: sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==} + dependencies: + '@hapi/hoek': 9.3.0 + dev: true + + /@sideway/formula@3.0.1: + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + dev: true + + /@sideway/pinpoint@2.0.0: + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + dev: true + + /@thewtex/zstddec@0.2.0: + resolution: {integrity: sha512-lIS+smrfa48WGlDVQSQSm0jBnwVp5XmfGJWU9q0J0fRFY9ohzK4s27Zg2SFMb1NWMp9RiANAdK+/q86EBGWR1Q==} + + /@types/emscripten@1.39.10: + resolution: {integrity: sha512-TB/6hBkYQJxsZHSqyeuO1Jt0AB/bW6G7rHt9g7lML7SOF6lbgcHvw/Lr+69iqN0qxgXLhWKScAon73JNnptuDw==} + + /@types/node@16.18.61: + resolution: {integrity: sha512-k0N7BqGhJoJzdh6MuQg1V1ragJiXTh8VUBAZTWjJ9cUq23SG0F0xavOwZbhiP4J3y20xd6jxKx+xNUhkMAi76Q==} + dev: true + + /@types/node@20.9.0: + resolution: {integrity: sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==} + dependencies: + undici-types: 5.26.5 + dev: true + + /@types/prop-types@15.7.10: + resolution: {integrity: sha512-mxSnDQxPqsZxmeShFH+uwQ4kO4gcJcGahjjMFeLbKE95IAZiiZyiEepGZjtXJ7hN/yfu0bu9xN2ajcU0JcxX6A==} + dev: true + + /@types/react@18.2.37: + resolution: {integrity: sha512-RGAYMi2bhRgEXT3f4B92WTohopH6bIXw05FuGlmJEnv/omEn190+QYEIYxIAuIBdKgboYYdVved2p1AxZVQnaw==} + dependencies: + '@types/prop-types': 15.7.10 + '@types/scheduler': 0.16.6 + csstype: 3.1.2 + dev: true + + /@types/scheduler@0.16.6: + resolution: {integrity: sha512-Vlktnchmkylvc9SnwwwozTv04L/e1NykF5vgoQ0XTmI8DD+wxfjQuHuvHS3p0r2jz2x2ghPs2h1FVeDirIteWA==} + dev: true + + /@types/sinonjs__fake-timers@8.1.1: + resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} + dev: true + + /@types/sizzle@2.3.6: + resolution: {integrity: sha512-m04Om5Gz6kbjUwAQ7XJJQ30OdEFsSmAVsvn4NYwcTRyMVpKKa1aPuESw1n2CxS5fYkOQv3nHgDKeNa8e76fUkw==} + dev: true + + /@types/trusted-types@2.0.6: + resolution: {integrity: sha512-HYtNooPvUY9WAVRBr4u+4Qa9fYD1ze2IUlAD3HoA6oehn1taGwBx3Oa52U4mTslTS+GAExKpaFu39Y5xUEwfjg==} + dev: true + + /@types/yauzl@2.10.3: + resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + requiresBuild: true + dependencies: + '@types/node': 20.9.0 + dev: true + optional: true + + /acorn-walk@8.3.0: + resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} + engines: {node: '>=0.4.0'} + dev: true + + /acorn@8.11.2: + resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /aggregate-error@3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + + /aggregate-error@4.0.1: + resolution: {integrity: sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==} + engines: {node: '>=12'} + dependencies: + clean-stack: 4.2.0 + indent-string: 5.0.0 + dev: true + + /ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} + dev: true + + /ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + dependencies: + type-fest: 0.21.3 + dev: true + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex@6.0.1: + resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + dependencies: + color-convert: 2.0.1 + dev: true + + /ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + dev: true + + /arch@2.2.0: + resolution: {integrity: sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==} + dev: true + + /arg@5.0.2: + resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true + + /argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + dependencies: + sprintf-js: 1.0.3 + dev: true + + /array-find-index@1.0.2: + resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} + engines: {node: '>=0.10.0'} + dev: true + + /arrgv@1.0.2: + resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} + engines: {node: '>=8.0.0'} + dev: true + + /arrify@3.0.0: + resolution: {integrity: sha512-tLkvA81vQG/XqE2mjDkGQHoOINtMHtysSnemrmoGe6PydDPMRbVugqyk4A6V/WDWEfm3l+0d8anA9r8cv/5Jaw==} + engines: {node: '>=12'} + dev: true + + /asn1@0.2.6: + resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} + dependencies: + safer-buffer: 2.1.2 + dev: true + + /assert-plus@1.0.0: + resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} + engines: {node: '>=0.8'} + dev: true + + /astral-regex@2.0.0: + resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} + engines: {node: '>=8'} + dev: true + + /async@3.2.5: + resolution: {integrity: sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==} + dev: true + + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + /at-least-node@1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /ava@5.3.1: + resolution: {integrity: sha512-Scv9a4gMOXB6+ni4toLuhAm9KYWEjsgBglJl+kMGI5+IVDt120CCDZyB5HNU9DjmLI2t4I0GbnxGLmmRfGTJGg==} + engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} + hasBin: true + peerDependencies: + '@ava/typescript': '*' + peerDependenciesMeta: + '@ava/typescript': + optional: true + dependencies: + acorn: 8.11.2 + acorn-walk: 8.3.0 + ansi-styles: 6.2.1 + arrgv: 1.0.2 + arrify: 3.0.0 + callsites: 4.1.0 + cbor: 8.1.0 + chalk: 5.3.0 + chokidar: 3.5.3 + chunkd: 2.0.1 + ci-info: 3.9.0 + ci-parallel-vars: 1.0.1 + clean-yaml-object: 0.1.0 + cli-truncate: 3.1.0 + code-excerpt: 4.0.0 + common-path-prefix: 3.0.0 + concordance: 5.0.4 + currently-unhandled: 0.4.1 + debug: 4.3.4(supports-color@8.1.1) + emittery: 1.0.1 + figures: 5.0.0 + globby: 13.2.2 + ignore-by-default: 2.1.0 + indent-string: 5.0.0 + is-error: 2.2.2 + is-plain-object: 5.0.0 + is-promise: 4.0.0 + matcher: 5.0.0 + mem: 9.0.2 + ms: 2.1.3 + p-event: 5.0.1 + p-map: 5.5.0 + picomatch: 2.3.1 + pkg-conf: 4.0.0 + plur: 5.1.0 + pretty-ms: 8.0.0 + resolve-cwd: 3.0.0 + stack-utils: 2.0.6 + strip-ansi: 7.1.0 + supertap: 3.0.1 + temp-dir: 3.0.0 + write-file-atomic: 5.0.1 + yargs: 17.7.2 + transitivePeerDependencies: + - supports-color + dev: true + + /aws-sign2@0.7.0: + resolution: {integrity: sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==} + dev: true + + /aws4@1.12.0: + resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} + dev: true + + /axios@0.27.2(debug@4.3.4): + resolution: {integrity: sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==} + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + form-data: 4.0.0 + transitivePeerDependencies: + - debug + dev: true + + /axios@1.6.1: + resolution: {integrity: sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==} + dependencies: + follow-redirects: 1.15.3(debug@4.3.4) + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + /balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + + /bcrypt-pbkdf@1.0.2: + resolution: {integrity: sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==} + dependencies: + tweetnacl: 0.14.5 + dev: true + + /binary-extensions@2.2.0: + resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} + engines: {node: '>=8'} + dev: true + + /blob-util@2.0.2: + resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} + dev: true + + /bluebird@3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /blueimp-md5@2.19.0: + resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} + dev: true + + /brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + dev: true + + /brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + + /braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.0.1 + dev: true + + /buffer-crc32@0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + + /buffer@5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + + /cachedir@2.4.0: + resolution: {integrity: sha512-9EtFOZR8g22CL7BWjJ9BUx1+A/djkofnyW3aOXZORNW2kxoUpx2h+uN2cOqwPmFhnpVmxg+KW2OjOSgChTEvsQ==} + engines: {node: '>=6'} + dev: true + + /call-bind@1.0.5: + resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} + dependencies: + function-bind: 1.1.2 + get-intrinsic: 1.2.2 + set-function-length: 1.1.1 + dev: true + + /callsites@4.1.0: + resolution: {integrity: sha512-aBMbD1Xxay75ViYezwT40aQONfr+pSXTHwNKvIXhXD6+LY3F1dLIcceoC5OZKBVHbXcysz1hL9D2w0JJIMXpUw==} + engines: {node: '>=12.20'} + dev: true + + /caseless@0.12.0: + resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} + dev: true + + /cbor@8.1.0: + resolution: {integrity: sha512-DwGjNW9omn6EwP70aXsn7FQJx5kO12tX0bZkaTjzdVFM6/7nhA4t0EENocKGx6D2Bch9PE2KzCUf5SceBdeijg==} + engines: {node: '>=12.19'} + dependencies: + nofilter: 3.1.0 + dev: true + + /chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + dev: true + + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /check-more-types@2.24.0: + resolution: {integrity: sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==} + engines: {node: '>= 0.8.0'} + dev: true + + /chokidar@3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} + engines: {node: '>= 8.10.0'} + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /chunkd@2.0.1: + resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} + dev: true + + /ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /ci-parallel-vars@1.0.1: + resolution: {integrity: sha512-uvzpYrpmidaoxvIQHM+rKSrigjOe9feHYbw4uOI2gdfe1C3xIlxO+kVXq83WQWNniTf8bAxVpy+cQeFQsMERKg==} + dev: true + + /clean-stack@2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /clean-stack@4.2.0: + resolution: {integrity: sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==} + engines: {node: '>=12'} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /clean-yaml-object@0.1.0: + resolution: {integrity: sha512-3yONmlN9CSAkzNwnRCiJQ7Q2xK5mWuEfL3PuTZcAUzhObbXsfsnMptJzXwz93nc5zn9V9TwCVMmV7w4xsm43dw==} + engines: {node: '>=0.10.0'} + dev: true + + /cli-cursor@3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-table3@0.6.3: + resolution: {integrity: sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==} + engines: {node: 10.* || >= 12.*} + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + dev: true + + /cli-truncate@2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + dev: true + + /cli-truncate@3.1.0: + resolution: {integrity: sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + slice-ansi: 5.0.0 + string-width: 5.1.2 + dev: true + + /cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + dev: true + + /code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + convert-to-spaces: 2.0.1 + dev: true + + /color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + dependencies: + color-name: 1.1.4 + dev: true + + /color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + dev: true + + /colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + dev: true + + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + + /comlink@4.4.1: + resolution: {integrity: sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==} + + /commander@6.2.1: + resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} + engines: {node: '>= 6'} + dev: true + + /commander@9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + + /common-path-prefix@3.0.0: + resolution: {integrity: sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==} + dev: true + + /common-tags@1.8.2: + resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} + engines: {node: '>=4.0.0'} + dev: true + + /composed-offset-position@0.0.4: + resolution: {integrity: sha512-vMlvu1RuNegVE0YsCDSV/X4X10j56mq7PCIyOKK74FxkXzGLwhOUmdkJLSdOBOMwWycobGUMgft2lp+YgTe8hw==} + dev: true + + /concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + dev: true + + /concordance@5.0.4: + resolution: {integrity: sha512-OAcsnTEYu1ARJqWVGwf4zh4JDfHZEaSNlNccFmt8YjB2l/n19/PF2viLINHc57vO4FKIAFl2FWASIGZZWZ2Kxw==} + engines: {node: '>=10.18.0 <11 || >=12.14.0 <13 || >=14'} + dependencies: + date-time: 3.1.0 + esutils: 2.0.3 + fast-diff: 1.3.0 + js-string-escape: 1.0.1 + lodash: 4.17.21 + md5-hex: 3.0.1 + semver: 7.5.4 + well-known-symbols: 2.0.0 + dev: true + + /convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /core-util-is@1.0.2: + resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + dev: true + + /cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + dev: true + + /csstype@3.1.2: + resolution: {integrity: sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==} + dev: true + + /currently-unhandled@0.4.1: + resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} + engines: {node: '>=0.10.0'} + dependencies: + array-find-index: 1.0.2 + dev: true + + /cypress@12.17.4: + resolution: {integrity: sha512-gAN8Pmns9MA5eCDFSDJXWKUpaL3IDd89N9TtIupjYnzLSmlpVr+ZR+vb4U/qaMp+lB6tBvAmt7504c3Z4RU5KQ==} + engines: {node: ^14.0.0 || ^16.0.0 || >=18.0.0} + hasBin: true + requiresBuild: true + dependencies: + '@cypress/request': 2.88.12 + '@cypress/xvfb': 1.2.4(supports-color@8.1.1) + '@types/node': 16.18.61 + '@types/sinonjs__fake-timers': 8.1.1 + '@types/sizzle': 2.3.6 + arch: 2.2.0 + blob-util: 2.0.2 + bluebird: 3.7.2 + buffer: 5.7.1 + cachedir: 2.4.0 + chalk: 4.1.2 + check-more-types: 2.24.0 + cli-cursor: 3.1.0 + cli-table3: 0.6.3 + commander: 6.2.1 + common-tags: 1.8.2 + dayjs: 1.11.10 + debug: 4.3.4(supports-color@8.1.1) + enquirer: 2.4.1 + eventemitter2: 6.4.7 + execa: 4.1.0 + executable: 4.1.1 + extract-zip: 2.0.1(supports-color@8.1.1) + figures: 3.2.0 + fs-extra: 9.1.0 + getos: 3.2.1 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + lazy-ass: 1.6.0 + listr2: 3.14.0(enquirer@2.4.1) + lodash: 4.17.21 + log-symbols: 4.1.0 + minimist: 1.2.8 + ospath: 1.2.2 + pretty-bytes: 5.6.0 + process: 0.11.10 + proxy-from-env: 1.0.0 + request-progress: 3.0.0 + semver: 7.5.4 + supports-color: 8.1.1 + tmp: 0.2.1 + untildify: 4.0.0 + yauzl: 2.10.0 + dev: true + + /dashdash@1.14.1: + resolution: {integrity: sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + dev: true + + /date-time@3.1.0: + resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} + engines: {node: '>=6'} + dependencies: + time-zone: 1.0.0 + dev: true + + /dayjs@1.11.10: + resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==} + dev: true + + /debug@3.2.7(supports-color@8.1.1): + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + supports-color: 8.1.1 + dev: true + + /debug@4.3.4(supports-color@8.1.1): + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.2 + supports-color: 8.1.1 + + /define-data-property@1.1.1: + resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} + engines: {node: '>= 0.4'} + dependencies: + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + /dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: true + + /duplexer@0.1.2: + resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + dev: true + + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /ecc-jsbn@0.1.2: + resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==} + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + dev: true + + /emittery@1.0.1: + resolution: {integrity: sha512-2ID6FdrMD9KDLldGesP6317G78K7km/kMcwItRtVFva7I/cSEOIaLpewaUb+YLXVwdAp3Ctfxh/V5zIl1sj7dQ==} + engines: {node: '>=14.16'} + dev: true + + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + + /enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 + dev: true + + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /escalade@3.1.1: + resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} + engines: {node: '>=6'} + dev: true + + /escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + dev: true + + /escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + dev: true + + /escape-string-regexp@5.0.0: + resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} + engines: {node: '>=12'} + dev: true + + /esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /event-stream@3.3.4: + resolution: {integrity: sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==} + dependencies: + duplexer: 0.1.2 + from: 0.1.7 + map-stream: 0.1.0 + pause-stream: 0.0.11 + split: 0.3.3 + stream-combiner: 0.0.4 + through: 2.3.8 + dev: true + + /eventemitter2@6.4.7: + resolution: {integrity: sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==} + dev: true + + /execa@4.1.0: + resolution: {integrity: sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 5.2.0 + human-signals: 1.1.1 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + dependencies: + cross-spawn: 7.0.3 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + dev: true + + /executable@4.1.1: + resolution: {integrity: sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==} + engines: {node: '>=4'} + dependencies: + pify: 2.3.0 + dev: true + + /extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + dev: true + + /extract-zip@2.0.1(supports-color@8.1.1): + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.3 + transitivePeerDependencies: + - supports-color + dev: true + + /extsprintf@1.3.0: + resolution: {integrity: sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==} + engines: {'0': node >=0.6.0} + dev: true + + /fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + dev: true + + /fast-glob@3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.5 + dev: true + + /fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + dependencies: + reusify: 1.0.4 + dev: true + + /fd-slicer@1.1.0: + resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + dependencies: + pend: 1.2.0 + dev: true + + /figures@3.2.0: + resolution: {integrity: sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==} + engines: {node: '>=8'} + dependencies: + escape-string-regexp: 1.0.5 + dev: true + + /figures@5.0.0: + resolution: {integrity: sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg==} + engines: {node: '>=14'} + dependencies: + escape-string-regexp: 5.0.0 + is-unicode-supported: 1.3.0 + dev: true + + /fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + dev: true + + /find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + dev: true + + /follow-redirects@1.15.3(debug@4.3.4): + resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + dependencies: + debug: 4.3.4(supports-color@8.1.1) + + /forever-agent@0.6.1: + resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} + dev: true + + /form-data@2.3.3: + resolution: {integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==} + engines: {node: '>= 0.12'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: true + + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + + /from@0.1.7: + resolution: {integrity: sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==} + dev: true + + /fs-extra@10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + /fs-extra@11.1.1: + resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra@9.1.0: + resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + /fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + dev: true + + /get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + dev: true + + /get-intrinsic@1.2.2: + resolution: {integrity: sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA==} + dependencies: + function-bind: 1.1.2 + has-proto: 1.0.1 + has-symbols: 1.0.3 + hasown: 2.0.0 + dev: true + + /get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} + dependencies: + pump: 3.0.0 + dev: true + + /get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /getos@3.2.1: + resolution: {integrity: sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==} + dependencies: + async: 3.2.5 + dev: true + + /getpass@0.1.7: + resolution: {integrity: sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==} + dependencies: + assert-plus: 1.0.0 + dev: true + + /glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + dev: true + + /glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + + /glob@8.1.0: + resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} + engines: {node: '>=12'} + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 5.1.6 + once: 1.4.0 + + /global-dirs@3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + + /globby@13.2.2: + resolution: {integrity: sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + dir-glob: 3.0.1 + fast-glob: 3.3.2 + ignore: 5.2.4 + merge2: 1.4.1 + slash: 4.0.0 + dev: true + + /gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + /has-property-descriptors@1.0.1: + resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} + dependencies: + get-intrinsic: 1.2.2 + dev: true + + /has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + dev: true + + /has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + dev: true + + /hasown@2.0.0: + resolution: {integrity: sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==} + engines: {node: '>= 0.4'} + dependencies: + function-bind: 1.1.2 + dev: true + + /http-signature@1.3.6: + resolution: {integrity: sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==} + engines: {node: '>=0.10'} + dependencies: + assert-plus: 1.0.0 + jsprim: 2.0.2 + sshpk: 1.18.0 + dev: true + + /human-signals@1.1.1: + resolution: {integrity: sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==} + engines: {node: '>=8.12.0'} + dev: true + + /human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + dev: true + + /ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + + /ignore-by-default@2.1.0: + resolution: {integrity: sha512-yiWd4GVmJp0Q6ghmM2B/V3oZGRmjrKLXvHR3TE1nfoXsmoggllfZUQe74EN0fJdPFZu2NIvNdrMMLm3OsV7Ohw==} + engines: {node: '>=10 <11 || >=12 <13 || >=14'} + dev: true + + /ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + dev: true + + /imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + + /indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + dev: true + + /inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini@2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + + /interpret@1.4.0: + resolution: {integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==} + engines: {node: '>= 0.10'} + dev: true + + /irregular-plurals@3.5.0: + resolution: {integrity: sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==} + engines: {node: '>=8'} + dev: true + + /is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + dependencies: + binary-extensions: 2.2.0 + dev: true + + /is-ci@3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.9.0 + dev: true + + /is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + dependencies: + hasown: 2.0.0 + dev: true + + /is-error@2.2.2: + resolution: {integrity: sha512-IOQqts/aHWbiisY5DuPJQ0gcbvaLFCa7fBa9xoLfxBZvQ+ZI/Zh9xoI7Gk+G64N0FdK4AbibytHht2tWgpJWLg==} + dev: true + + /is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + dev: true + + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + dev: true + + /is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + dev: true + + /is-installed-globally@0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + dev: true + + /is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + dev: true + + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-object@5.0.0: + resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + engines: {node: '>=0.10.0'} + dev: true + + /is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + dev: true + + /is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + dev: true + + /is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: true + + /is-unicode-supported@0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + + /is-unicode-supported@1.3.0: + resolution: {integrity: sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==} + engines: {node: '>=12'} + dev: true + + /isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isstream@0.1.2: + resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} + dev: true + + /itk-wasm@1.0.0-b.154: + resolution: {integrity: sha512-bzwOpA4kaNNC2SUTk2wWfHdg+4G6kW8KdMcp3kChhKWzR3T76bV9yybDsuoYq/6aWFQtIgEJLMFcTUpwk0PodA==} + hasBin: true + dependencies: + '@babel/runtime': 7.23.2 + '@thewtex/zstddec': 0.2.0 + '@types/emscripten': 1.39.10 + axios: 1.6.1 + comlink: 4.4.1 + commander: 9.5.0 + fs-extra: 10.1.0 + glob: 8.1.0 + markdown-table: 3.0.3 + mime-types: 2.1.35 + wasm-feature-detect: 1.6.1 + transitivePeerDependencies: + - debug + + /joi@17.11.0: + resolution: {integrity: sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==} + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.4 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + dev: true + + /js-string-escape@1.0.1: + resolution: {integrity: sha512-Smw4xcfIQ5LVjAOuJCvN/zIodzA/BBSsluuoSykP+lUvScIi4U6RJLfwHet5cxFnCswUjISV8oAXaqaJDY3chg==} + engines: {node: '>= 0.8'} + dev: true + + /js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + dev: true + + /jsbn@0.1.1: + resolution: {integrity: sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==} + dev: true + + /json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + dev: true + + /json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + dev: true + + /jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + /jsprim@2.0.2: + resolution: {integrity: sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.4.0 + verror: 1.10.0 + dev: true + + /lazy-ass@1.6.0: + resolution: {integrity: sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==} + engines: {node: '> 0.8'} + dev: true + + /listr2@3.14.0(enquirer@2.4.1): + resolution: {integrity: sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==} + engines: {node: '>=10.0.0'} + peerDependencies: + enquirer: '>= 2.3.0 < 3' + peerDependenciesMeta: + enquirer: + optional: true + dependencies: + cli-truncate: 2.1.0 + colorette: 2.0.20 + enquirer: 2.4.1 + log-update: 4.0.0 + p-map: 4.0.0 + rfdc: 1.3.0 + rxjs: 7.8.1 + through: 2.3.8 + wrap-ansi: 7.0.0 + dev: true + + /lit-element@4.0.1: + resolution: {integrity: sha512-OxRMJem4HKZt0320HplLkBPoi4KHiEHoPHKd8Lzf07ZQVAOKIjZ32yPLRKRDEolFU1RgrQBfSHQMoxKZ72V3Kw==} + dependencies: + '@lit-labs/ssr-dom-shim': 1.1.2 + '@lit/reactive-element': 2.0.1 + lit-html: 3.0.2 + dev: true + + /lit-html@3.0.2: + resolution: {integrity: sha512-Q1A5lHza3bnmxoWJn6yS6vQZQdExl4fghk8W1G+jnAEdoFNYo5oeBBb/Ol7zSEdKd3TR7+r0zsJQyuWEVguiyQ==} + dependencies: + '@types/trusted-types': 2.0.6 + dev: true + + /lit@3.0.2: + resolution: {integrity: sha512-ZoVUPGgXOQocP4OvxehEOBmC4rWB4cRYDPaz7aFmH8DFytsCi/NeACbr4C6vNPGDEC07BrhUos7uVNayDKLQ2Q==} + dependencies: + '@lit/reactive-element': 2.0.1 + lit-element: 4.0.1 + lit-html: 3.0.2 + dev: true + + /load-json-file@7.0.1: + resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-locate: 6.0.0 + dev: true + + /lodash.once@4.1.1: + resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} + dev: true + + /lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /log-symbols@4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + + /log-update@4.0.0: + resolution: {integrity: sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==} + engines: {node: '>=10'} + dependencies: + ansi-escapes: 4.3.2 + cli-cursor: 3.1.0 + slice-ansi: 4.0.0 + wrap-ansi: 6.2.0 + dev: true + + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: true + + /map-age-cleaner@0.1.3: + resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} + engines: {node: '>=6'} + dependencies: + p-defer: 1.0.0 + dev: true + + /map-stream@0.1.0: + resolution: {integrity: sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==} + dev: true + + /markdown-table@3.0.3: + resolution: {integrity: sha512-Z1NL3Tb1M9wH4XESsCDEksWoKTdlUafKc4pt0GRwjUyXaCFZ+dc3g2erqB6zm3szA2IUSi7VnPI+o/9jnxh9hw==} + + /matcher@5.0.0: + resolution: {integrity: sha512-s2EMBOWtXFc8dgqvoAzKJXxNHibcdJMV0gwqKUaw9E2JBJuGUK7DrNKrA6g/i+v72TT16+6sVm5mS3thaMLQUw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + escape-string-regexp: 5.0.0 + dev: true + + /md5-hex@3.0.1: + resolution: {integrity: sha512-BUiRtTtV39LIJwinWBjqVsU9xhdnz7/i889V859IBFpuqGAj6LuOvHv5XLbgZ2R7ptJoJaEcxkv88/h25T7Ciw==} + engines: {node: '>=8'} + dependencies: + blueimp-md5: 2.19.0 + dev: true + + /mem@9.0.2: + resolution: {integrity: sha512-F2t4YIv9XQUBHt6AOJ0y7lSmP1+cY7Fm1DRh9GClTGzKST7UWLMx6ly9WZdLH/G/ppM5RL4MlQfRT71ri9t19A==} + engines: {node: '>=12.20'} + dependencies: + map-age-cleaner: 0.1.3 + mimic-fn: 4.0.0 + dev: true + + /merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + dev: true + + /merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + dev: true + + /micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.2 + picomatch: 2.3.1 + dev: true + + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + + /mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + dev: true + + /mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + dev: true + + /minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + dev: true + + /minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + + /minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + /ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /nanoid@3.3.7: + resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + dev: true + + /nofilter@3.1.0: + resolution: {integrity: sha512-l2NNj07e9afPnhAhvgVrCD/oy2Ai1yfLpuo3EpiO1jFTsB4sFz6oIfAfSZyQzVpkZQ9xS8ZS5g1jCBgq4Hwo0g==} + engines: {node: '>=12.19'} + dev: true + + /normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + dev: true + + /npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + dependencies: + path-key: 3.1.1 + dev: true + + /object-inspect@1.13.1: + resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} + dev: true + + /once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + dependencies: + mimic-fn: 2.1.0 + dev: true + + /ospath@1.2.2: + resolution: {integrity: sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA==} + dev: true + + /p-defer@1.0.0: + resolution: {integrity: sha512-wB3wfAxZpk2AzOfUMJNL+d36xothRSyj8EXOa4f6GMqYDN9BJaaSISbsk+wS9abmnebVw95C2Kb5t85UmpCxuw==} + engines: {node: '>=4'} + dev: true + + /p-event@5.0.1: + resolution: {integrity: sha512-dd589iCQ7m1L0bmC5NLlVYfy3TbBEsMUfWx9PyAgPeIcFZ/E2yaTZ4Rz4MiBmmJShviiftHVXOqfnfzJ6kyMrQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-timeout: 5.1.0 + dev: true + + /p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + yocto-queue: 1.0.0 + dev: true + + /p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + p-limit: 4.0.0 + dev: true + + /p-map@4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-map@5.5.0: + resolution: {integrity: sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==} + engines: {node: '>=12'} + dependencies: + aggregate-error: 4.0.1 + dev: true + + /p-timeout@5.1.0: + resolution: {integrity: sha512-auFDyzzzGZZZdHz3BtET9VEz0SE/uMEAx7uWfGPucfzEwwe/xH0iVeZibQmANYE/hp9T2+UUZT5m+BKyrDp3Ew==} + engines: {node: '>=12'} + dev: true + + /parse-ms@3.0.0: + resolution: {integrity: sha512-Tpb8Z7r7XbbtBTrM9UhpkzzaMrqA2VXMT3YChzYltwV3P3pM6t8wl7TvpMnSTosz1aQAdVib7kdoys7vYOPerw==} + engines: {node: '>=12'} + dev: true + + /path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + dev: true + + /path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + dev: true + + /path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true + + /path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: true + + /pause-stream@0.0.11: + resolution: {integrity: sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==} + dependencies: + through: 2.3.8 + dev: true + + /pend@1.2.0: + resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + dev: true + + /performance-now@2.1.0: + resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} + dev: true + + /picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + dev: true + + /picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + dev: true + + /pify@2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + + /pkg-conf@4.0.0: + resolution: {integrity: sha512-7dmgi4UY4qk+4mj5Cd8v/GExPo0K+SlY+hulOSdfZ/T6jVH6//y7NtzZo5WrfhDBxuQ0jCa7fLZmNaNh7EWL/w==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + find-up: 6.3.0 + load-json-file: 7.0.1 + dev: true + + /plur@5.1.0: + resolution: {integrity: sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + irregular-plurals: 3.5.0 + dev: true + + /postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.7 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + + /pretty-bytes@5.6.0: + resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==} + engines: {node: '>=6'} + dev: true + + /pretty-ms@8.0.0: + resolution: {integrity: sha512-ASJqOugUF1bbzI35STMBUpZqdfYKlJugy6JBziGi2EE+AL5JPJGSzvpeVXojxrr0ViUYoToUjb5kjSEGf7Y83Q==} + engines: {node: '>=14.16'} + dependencies: + parse-ms: 3.0.0 + dev: true + + /process@0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: true + + /proxy-from-env@1.0.0: + resolution: {integrity: sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==} + dev: true + + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + /ps-tree@1.2.0: + resolution: {integrity: sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==} + engines: {node: '>= 0.10'} + hasBin: true + dependencies: + event-stream: 3.3.4 + dev: true + + /psl@1.9.0: + resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} + dev: true + + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: true + + /punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + dev: true + + /qr-creator@1.0.0: + resolution: {integrity: sha512-C0cqfbS1P5hfqN4NhsYsUXePlk9BO+a45bAQ3xLYjBL3bOIFzoVEjs79Fado9u9BPBD3buHi3+vY+C8tHh4qMQ==} + dev: true + + /qs@6.10.4: + resolution: {integrity: sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==} + engines: {node: '>=0.6'} + dependencies: + side-channel: 1.0.4 + dev: true + + /querystringify@2.2.0: + resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + dev: true + + /queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + dev: true + + /readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + dependencies: + picomatch: 2.3.1 + dev: true + + /rechoir@0.6.2: + resolution: {integrity: sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==} + engines: {node: '>= 0.10'} + dependencies: + resolve: 1.22.8 + dev: true + + /regenerator-runtime@0.14.0: + resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} + + /request-progress@3.0.0: + resolution: {integrity: sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg==} + dependencies: + throttleit: 1.0.0 + dev: true + + /require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + dev: true + + /requires-port@1.0.0: + resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + dev: true + + /resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + dependencies: + resolve-from: 5.0.0 + dev: true + + /resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + dev: true + + /resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + dependencies: + is-core-module: 2.13.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + dev: true + + /restore-cursor@3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + dev: true + + /rfdc@1.3.0: + resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} + dev: true + + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: true + + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + dev: true + + /rxjs@7.8.1: + resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} + dependencies: + tslib: 2.6.2 + dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + + /safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: true + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /serialize-error@7.0.1: + resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} + engines: {node: '>=10'} + dependencies: + type-fest: 0.13.1 + dev: true + + /set-function-length@1.1.1: + resolution: {integrity: sha512-VoaqjbBJKiWtg4yRcKBQ7g7wnGnLV3M8oLvVWwOk2PdYY6PEFegR1vezXR0tw6fZGF9csVakIRjrJiy2veSBFQ==} + engines: {node: '>= 0.4'} + dependencies: + define-data-property: 1.1.1 + get-intrinsic: 1.2.2 + gopd: 1.0.1 + has-property-descriptors: 1.0.1 + dev: true + + /shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + dependencies: + shebang-regex: 3.0.0 + dev: true + + /shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + dev: true + + /shelljs@0.8.5: + resolution: {integrity: sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==} + engines: {node: '>=4'} + hasBin: true + dependencies: + glob: 7.2.3 + interpret: 1.4.0 + rechoir: 0.6.2 + dev: true + + /shx@0.3.4: + resolution: {integrity: sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==} + engines: {node: '>=6'} + hasBin: true + dependencies: + minimist: 1.2.8 + shelljs: 0.8.5 + dev: true + + /side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + dependencies: + call-bind: 1.0.5 + get-intrinsic: 1.2.2 + object-inspect: 1.13.1 + dev: true + + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + dev: true + + /slash@4.0.0: + resolution: {integrity: sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==} + engines: {node: '>=12'} + dev: true + + /slice-ansi@3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi@4.0.0: + resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + + /slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + dev: true + + /source-map-js@1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} + engines: {node: '>=0.10.0'} + dev: true + + /split@0.3.3: + resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} + dependencies: + through: 2.3.8 + dev: true + + /sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + dev: true + + /sshpk@1.18.0: + resolution: {integrity: sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==} + engines: {node: '>=0.10.0'} + hasBin: true + dependencies: + asn1: 0.2.6 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + dev: true + + /stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + dependencies: + escape-string-regexp: 2.0.0 + dev: true + + /start-server-and-test@2.0.2: + resolution: {integrity: sha512-4sGS2QmETUwqeBUqtTLP7OqXp3PdDnevaWlPlrFQgn8+7uCgVg4Do7/H/ZhAAVyvnL3DqKyANhnLgcgxrjhrMA==} + engines: {node: '>=16'} + hasBin: true + dependencies: + arg: 5.0.2 + bluebird: 3.7.2 + check-more-types: 2.24.0 + debug: 4.3.4(supports-color@8.1.1) + execa: 5.1.1 + lazy-ass: 1.6.0 + ps-tree: 1.2.0 + wait-on: 7.1.0(debug@4.3.4) + transitivePeerDependencies: + - supports-color + dev: true + + /stream-combiner@0.0.4: + resolution: {integrity: sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==} + dependencies: + duplexer: 0.1.2 + dev: true + + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.0.1 + dev: true + + /strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + dev: true + + /supertap@3.0.1: + resolution: {integrity: sha512-u1ZpIBCawJnO+0QePsEiOknOfCRq0yERxiAchT0i4li0WHNUJbf0evXXSXOcCAR4M8iMDoajXYmstm/qO81Isw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + indent-string: 5.0.0 + js-yaml: 3.14.1 + serialize-error: 7.0.1 + strip-ansi: 7.1.0 + dev: true + + /supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + dependencies: + has-flag: 4.0.0 + dev: true + + /supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + dependencies: + has-flag: 4.0.0 + + /supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + dev: true + + /temp-dir@3.0.0: + resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} + engines: {node: '>=14.16'} + dev: true + + /throttleit@1.0.0: + resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} + dev: true + + /through@2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /time-zone@1.0.0: + resolution: {integrity: sha512-TIsDdtKo6+XrPtiTm1ssmMngN1sAhyKnTO2kunQWqNPWIVvCm15Wmw4SWInwTVgJ5u/Tr04+8Ei9TNcw4x4ONA==} + engines: {node: '>=4'} + dev: true + + /tmp@0.2.1: + resolution: {integrity: sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==} + engines: {node: '>=8.17.0'} + dependencies: + rimraf: 3.0.2 + dev: true + + /to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + dev: true + + /tough-cookie@4.1.3: + resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} + engines: {node: '>=6'} + dependencies: + psl: 1.9.0 + punycode: 2.3.1 + universalify: 0.2.0 + url-parse: 1.5.10 + dev: true + + /tslib@2.6.2: + resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + dev: true + + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: true + + /tweetnacl@0.14.5: + resolution: {integrity: sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==} + dev: true + + /type-fest@0.13.1: + resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} + engines: {node: '>=10'} + dev: true + + /type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + dev: true + + /typescript@5.2.2: + resolution: {integrity: sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==} + engines: {node: '>=14.17'} + hasBin: true + dev: true + + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + dev: true + + /universalify@0.2.0: + resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} + engines: {node: '>= 4.0.0'} + dev: true + + /universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + /untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + dev: true + + /url-parse@1.5.10: + resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + dependencies: + querystringify: 2.2.0 + requires-port: 1.0.0 + dev: true + + /uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + + /verror@1.10.0: + resolution: {integrity: sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==} + engines: {'0': node >=0.6.0} + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.3.0 + dev: true + + /vite-plugin-static-copy@0.17.0(vite@4.5.0): + resolution: {integrity: sha512-2HpNbHfDt8SDy393AGXh9llHkc8FJMQkI8s3T5WsH3SWLMO+f5cFIyPErl4yGKU9Uh3Vaqsd4lHZYTf042fQ2A==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^3.0.0 || ^4.0.0 + dependencies: + chokidar: 3.5.3 + fast-glob: 3.3.2 + fs-extra: 11.1.1 + picocolors: 1.0.0 + vite: 4.5.0(@types/node@20.9.0) + dev: true + + /vite@4.5.0(@types/node@20.9.0): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + '@types/node': 20.9.0 + esbuild: 0.18.20 + postcss: 8.4.31 + rollup: 3.29.4 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /wait-on@7.1.0(debug@4.3.4): + resolution: {integrity: sha512-U7TF/OYYzAg+OoiT/B8opvN48UHt0QYMi4aD3PjRFpybQ+o6czQF8Ig3SKCCMJdxpBrCalIJ4O00FBof27Fu9Q==} + engines: {node: '>=12.0.0'} + hasBin: true + dependencies: + axios: 0.27.2(debug@4.3.4) + joi: 17.11.0 + lodash: 4.17.21 + minimist: 1.2.8 + rxjs: 7.8.1 + transitivePeerDependencies: + - debug + dev: true + + /wasm-feature-detect@1.6.1: + resolution: {integrity: sha512-R1i9ED8UlLu/foILNB1ck9XS63vdtqU/tP1MCugVekETp/ySCrBZRk5I/zI67cI1wlQYeSonNm1PLjDHZDNg6g==} + + /well-known-symbols@2.0.0: + resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} + engines: {node: '>=6'} + dev: true + + /which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + dev: true + + /wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + dev: true + + /y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + dev: true + + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true + + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + + /yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + dependencies: + cliui: 8.0.1 + escalade: 3.1.1 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + dev: true + + /yauzl@2.10.0: + resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + dependencies: + buffer-crc32: 0.2.13 + fd-slicer: 1.1.0 + dev: true + + /yocto-queue@1.0.0: + resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} + engines: {node: '>=12.20'} + dev: true diff --git a/packages/compare-images/typescript/src/index-worker-embedded.min.ts b/packages/compare-images/typescript/src/index-worker-embedded.min.ts new file mode 100644 index 000000000..737584dee --- /dev/null +++ b/packages/compare-images/typescript/src/index-worker-embedded.min.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.min.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' diff --git a/packages/compare-images/typescript/src/index-worker-embedded.ts b/packages/compare-images/typescript/src/index-worker-embedded.ts new file mode 100644 index 000000000..cdbc5d63d --- /dev/null +++ b/packages/compare-images/typescript/src/index-worker-embedded.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' \ No newline at end of file diff --git a/packages/compare-images/typescript/src/index.ts b/packages/compare-images/typescript/src/index.ts index 548bf9827..d02f4ed6a 100644 --- a/packages/compare-images/typescript/src/index.ts +++ b/packages/compare-images/typescript/src/index.ts @@ -1,4 +1,5 @@ export * from './pipelines-base-url.js' +export * from './pipeline-worker-url.js' import CompareImagesMetric from './compare-images-metric.js' export type { CompareImagesMetric } diff --git a/packages/compare-images/typescript/src/package.json b/packages/compare-images/typescript/src/package.json new file mode 120000 index 000000000..4e26811d4 --- /dev/null +++ b/packages/compare-images/typescript/src/package.json @@ -0,0 +1 @@ +../package.json \ No newline at end of file diff --git a/packages/compare-images/typescript/src/pipeline-worker-url.ts b/packages/compare-images/typescript/src/pipeline-worker-url.ts index ec82af9e1..39118ba4a 100644 --- a/packages/compare-images/typescript/src/pipeline-worker-url.ts +++ b/packages/compare-images/typescript/src/pipeline-worker-url.ts @@ -1,8 +1,8 @@ import { getPipelineWorkerUrl as itkWasmGetPipelineWorkerUrl } from 'itk-wasm' -import packageJson from '../package.json' let pipelineWorkerUrl: string | URL | null | undefined -const defaultPipelineWorkerUrl = `https://cdn.jsdelivr.net/npm/@itk-wasm/compare-images@${packageJson.version}/dist/web-workers/pipeline.worker.js` +// Use the version shipped with an app's bundler +const defaultPipelineWorkerUrl = null export function setPipelineWorkerUrl (workerUrl: string | URL | null): void { pipelineWorkerUrl = workerUrl diff --git a/packages/compare-images/typescript/src/pipelines-base-url.ts b/packages/compare-images/typescript/src/pipelines-base-url.ts index f7f222511..d2021e663 100644 --- a/packages/compare-images/typescript/src/pipelines-base-url.ts +++ b/packages/compare-images/typescript/src/pipelines-base-url.ts @@ -1,5 +1,5 @@ import { getPipelinesBaseUrl as itkWasmGetPipelinesBaseUrl } from 'itk-wasm' -import packageJson from '../package.json' +import packageJson from './package.json' let pipelinesBaseUrl: string | URL | undefined let defaultPipelinesBaseUrl: string | URL = `https://cdn.jsdelivr.net/npm/@itk-wasm/compare-images@${packageJson.version}/dist/pipelines` diff --git a/packages/compare-images/typescript/tsconfig.json b/packages/compare-images/typescript/tsconfig.json index 4eba4b8ec..242f02a0c 100644 --- a/packages/compare-images/typescript/tsconfig.json +++ b/packages/compare-images/typescript/tsconfig.json @@ -16,8 +16,10 @@ "noImplicitReturns": true, "skipLibCheck": true, "declaration": true, - "emitDeclarationOnly": true, - "declarationDir": "dist/" + "emitDeclarationOnly": false, + "outDir": "dist/", + "rootDir": "src/" }, - "include": ["src/*.ts"] + "include": ["src/*.ts"], + "exclude": ["src/index-worker-embedded*.ts"] } From cefe3a87411333d74273f99f858a502f4b04adf5 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 8 Nov 2023 22:24:37 -0500 Subject: [PATCH 21/23] build(dicom): bump typescript for itk-wasm 1.0.0-b.154 --- .../itkwasm_dicom_emscripten/_version.py | 2 +- .../itkwasm_dicom_emscripten/js_package.py | 6 +- .../itkwasm-dicom-emscripten/pyproject.toml | 3 +- .../itkwasm_dicom_wasi/_version.py | 2 +- .../itkwasm-dicom/itkwasm_dicom/_version.py | 2 +- .../typescript/build/rollup.browser.config.js | 51 -- .../typescript/build/rollup.node.config.js | 32 - .../dicom/typescript/build/vite.config.js | 7 + packages/dicom/typescript/package.json | 39 +- packages/dicom/typescript/pnpm-lock.yaml | 603 ++++-------------- .../src/index-worker-embedded.min.ts | 9 + .../typescript/src/index-worker-embedded.ts | 9 + packages/dicom/typescript/src/package.json | 1 + .../typescript/src/pipeline-worker-url.ts | 4 +- .../typescript/src/pipelines-base-url.ts | 2 +- .../typescript/src/read-dicom-tags-node.ts | 2 +- .../read-dicom-encapsulated-pdf-controller.ts | 2 +- ...read-image-dicom-file-series-controller.ts | 2 +- .../structured-report-to-html-controller.ts | 2 +- packages/dicom/typescript/test/node/dcmtk.js | 6 +- packages/dicom/typescript/test/node/gdcm.js | 2 +- packages/dicom/typescript/tsconfig.json | 8 +- 22 files changed, 173 insertions(+), 623 deletions(-) delete mode 100644 packages/dicom/typescript/build/rollup.browser.config.js delete mode 100644 packages/dicom/typescript/build/rollup.node.config.js create mode 100644 packages/dicom/typescript/src/index-worker-embedded.min.ts create mode 100644 packages/dicom/typescript/src/index-worker-embedded.ts create mode 120000 packages/dicom/typescript/src/package.json diff --git a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py index ce1305bf4..ba7be38e4 100644 --- a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py +++ b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/_version.py @@ -1 +1 @@ -__version__ = "4.0.0" +__version__ = "5.0.0" diff --git a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py index 77d5d3bb8..18d0bc599 100644 --- a/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py +++ b/packages/dicom/python/itkwasm-dicom-emscripten/itkwasm_dicom_emscripten/js_package.py @@ -1,6 +1,8 @@ +# Generated file. To retain edits, remove this comment. + from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ - -default_config = JsPackageConfig(f"https://cdn.jsdelivr.net/npm/@itk-wasm/dicom@{__version__}/dist/bundles/dicom.js") +default_js_module = """data:text/javascript;base64,dmFyIEV0PSIxLjAuMC1iLjE1NCIsWD1FdDt2YXIgZHQ9e3BpcGVsaW5lV29ya2VyVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay13YXNtQCR7WH0vZGlzdC9jb3JlL3dlYi13b3JrZXJzL2J1bmRsZXMvcGlwZWxpbmUubWluLndvcmtlci5qc2AsaW1hZ2VJT1VybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstaW1hZ2UtaW9AJHtYfWAsbWVzaElPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1tZXNoLWlvQCR7WH1gLHBpcGVsaW5lc1VybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstd2FzbUAke1h9L2Rpc3QvcGlwZWxpbmVzYH0sdj1kdDt2YXIgUXQ9e1RleHRGaWxlOiJJbnRlcmZhY2VUZXh0RmlsZSIsQmluYXJ5RmlsZToiSW50ZXJmYWNlQmluYXJ5RmlsZSIsVGV4dFN0cmVhbToiSW50ZXJmYWNlVGV4dFN0cmVhbSIsQmluYXJ5U3RyZWFtOiJJbnRlcmZhY2VCaW5hcnlTdHJlYW0iLEltYWdlOiJJbnRlcmZhY2VJbWFnZSIsTWVzaDoiSW50ZXJmYWNlTWVzaCIsUG9seURhdGE6IkludGVyZmFjZVBvbHlEYXRhIixKc29uQ29tcGF0aWJsZToiSW50ZXJmYWNlSnNvbkNvbXBhdGlibGUifSxFPVF0O3ZhciBwdD17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEQ9cHQ7dmFyIG10PXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxIPW10O3ZhciBodD17VGV4dDoiVGV4dCIsQmluYXJ5OiJCaW5hcnkiLEltYWdlOiJJbWFnZSIsTWVzaDoiTWVzaCJ9LGs9aHQ7dmFyIHl0PXtVbmtub3duOiJVbmtub3duIixTY2FsYXI6IlNjYWxhciIsUkdCOiJSR0IiLFJHQkE6IlJHQkEiLE9mZnNldDoiT2Zmc2V0IixWZWN0b3I6IlZlY3RvciIsUG9pbnQ6IlBvaW50IixDb3ZhcmlhbnRWZWN0b3I6IkNvdmFyaWFudFZlY3RvciIsU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvcjoiU3ltbWV0cmljU2Vjb25kUmFua1RlbnNvciIsRGlmZnVzaW9uVGVuc29yM0Q6IkRpZmZ1c2lvblRlbnNvcjNEIixDb21wbGV4OiJDb21wbGV4IixGaXhlZEFycmF5OiJGaXhlZEFycmF5IixBcnJheToiQXJyYXkiLE1hdHJpeDoiTWF0cml4IixWYXJpYWJsZUxlbmd0aFZlY3RvcjoiVmFyaWFibGVMZW5ndGhWZWN0b3IiLFZhcmlhYmxlU2l6ZU1hdHJpeDoiVmFyaWFibGVTaXplTWF0cml4In0sc2U9eXQ7ZnVuY3Rpb24gd3QoQSx0LGUscixuKXtBW3IrZSp0XT1ufXZhciBJZT13dDt2YXIgRkE9Y2xhc3N7Y29uc3RydWN0b3IodD0yLGU9RC5VSW50OCxyPXNlLlNjYWxhcixuPTEpe3RoaXMuZGltZW5zaW9uPXQsdGhpcy5jb21wb25lbnRUeXBlPWUsdGhpcy5waXhlbFR5cGU9cix0aGlzLmNvbXBvbmVudHM9bn19LGdlPUZBO3ZhciBrQT1jbGFzc3tjb25zdHJ1Y3Rvcih0PW5ldyBnZSl7dGhpcy5pbWFnZVR5cGU9dCx0aGlzLm5hbWU9ImltYWdlIjtsZXQgZT10LmRpbWVuc2lvbjt0aGlzLm9yaWdpbj1uZXcgQXJyYXkoZSksdGhpcy5vcmlnaW4uZmlsbCgwKSx0aGlzLnNwYWNpbmc9bmV3IEFycmF5KGUpLHRoaXMuc3BhY2luZy5maWxsKDEpLHRoaXMuZGlyZWN0aW9uPW5ldyBGbG9hdDY0QXJyYXkoZSplKSx0aGlzLmRpcmVjdGlvbi5maWxsKDApO2ZvcihsZXQgcj0wO3I8ZTtyKyspSWUodGhpcy5kaXJlY3Rpb24sZSxyLHIsMSk7dGhpcy5zaXplPW5ldyBBcnJheShlKSx0aGlzLnNpemUuZmlsbCgwKSx0aGlzLm1ldGFkYXRhPW5ldyBNYXAsdGhpcy5kYXRhPW51bGx9fSxsZT1rQTtmdW5jdGlvbiBEdChBLHQpe2xldCBlPW51bGw7c3dpdGNoKEEpe2Nhc2UgRC5VSW50ODp7ZT1uZXcgVWludDhBcnJheSh0KTticmVha31jYXNlIEQuSW50ODp7ZT1uZXcgSW50OEFycmF5KHQpO2JyZWFrfWNhc2UgRC5VSW50MTY6e2U9bmV3IFVpbnQxNkFycmF5KHQpO2JyZWFrfWNhc2UgRC5JbnQxNjp7ZT1uZXcgSW50MTZBcnJheSh0KTticmVha31jYXNlIEQuVUludDMyOntlPW5ldyBVaW50MzJBcnJheSh0KTticmVha31jYXNlIEQuSW50MzI6e2U9bmV3IEludDMyQXJyYXkodCk7YnJlYWt9Y2FzZSBELlVJbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnVWludDY0QXJyYXk9PSJmdW5jdGlvbiI/ZT1uZXcgQmlnVWludDY0QXJyYXkodCk6ZT1uZXcgVWludDhBcnJheSh0KTticmVha31jYXNlIEQuSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ0ludDY0QXJyYXk9PSJmdW5jdGlvbiI/ZT1uZXcgQmlnSW50NjRBcnJheSh0KTplPW5ldyBVaW50OEFycmF5KHQpO2JyZWFrfWNhc2UgSC5GbG9hdDMyOntlPW5ldyBGbG9hdDMyQXJyYXkodCk7YnJlYWt9Y2FzZSBILkZsb2F0NjQ6e2U9bmV3IEZsb2F0NjRBcnJheSh0KTticmVha31jYXNlIm51bGwiOntlPW51bGw7YnJlYWt9Y2FzZSBudWxsOntlPW51bGw7YnJlYWt9ZGVmYXVsdDp0aHJvdyBuZXcgRXJyb3IoIlR5cGUgaXMgbm90IHN1cHBvcnRlZCBhcyBhIFR5cGVkQXJyYXkiKX1yZXR1cm4gZX12YXIgdz1EdDtmdW5jdGlvbiBTdChBKXtpZihBLmxlbmd0aDwxKXRocm93IEVycm9yKCJBdCBsZWFzdCBvbmUgaW1hZ2VzIGlzIHJlcXVpcmVkLiIpO2xldCB0PUFbMF07aWYodC5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiSW1hZ2UgZGF0YSBpcyBudWxsLiIpO2xldCBlPW5ldyBsZSh0LmltYWdlVHlwZSk7ZS5vcmlnaW49QXJyYXkuZnJvbSh0Lm9yaWdpbiksZS5zcGFjaW5nPUFycmF5LmZyb20odC5zcGFjaW5nKTtsZXQgcj1lLmltYWdlVHlwZS5kaW1lbnNpb247ZS5kaXJlY3Rpb249dC5kaXJlY3Rpb24uc2xpY2UoKTtsZXQgbj1yLTE7ZS5zaXplPUFycmF5LmZyb20odC5zaXplKTtsZXQgYT1BLnJlZHVjZSgocyxDKT0+cytDLnNpemVbbl0sMCk7ZS5zaXplW25dPWE7bGV0IGk9ZS5zaXplLnJlZHVjZSgocyxDKT0+cypDLDEpKmUuaW1hZ2VUeXBlLmNvbXBvbmVudHMsbD10LmRhdGEuY29uc3RydWN0b3I7ZS5kYXRhPW5ldyBsKGkpO2xldCB1PWUuaW1hZ2VUeXBlLmNvbXBvbmVudHM7Zm9yKGxldCBzPTA7czxlLnNpemUubGVuZ3RoLTE7cysrKXUqPWUuc2l6ZVtzXTtsZXQgbz0wO2lmKGUuZGF0YSE9bnVsbClmb3IobGV0IHM9MDtzPEEubGVuZ3RoO3MrKyllLmRhdGEuc2V0KEFbc10uZGF0YSx1Km8pLG8rPUFbc10uc2l6ZVtuXTtlbHNlIHRocm93IEVycm9yKCJDb3VsZCBub3QgY3JlYXRlIHJlc3VsdCBpbWFnZSBkYXRhLiIpO3JldHVybiBlfXZhciBSQT1TdDt2YXIgYnQ9ZnVuY3Rpb24oQSx0KXt2YXIgZT17fTtmb3IodmFyIHIgaW4gQSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoQSxyKSYmdC5pbmRleE9mKHIpPDAmJihlW3JdPUFbcl0pO2lmKEEhPW51bGwmJnR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzPT0iZnVuY3Rpb24iKWZvcih2YXIgbj0wLHI9T2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhBKTtuPHIubGVuZ3RoO24rKyl0LmluZGV4T2YocltuXSk8MCYmT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKEEscltuXSkmJihlW3Jbbl1dPUFbcltuXV0pO3JldHVybiBlfSxVQT1jbGFzc3tjb25zdHJ1Y3Rvcih0LGUpe3RoaXMuZmNuPWUsdGhpcy53b3JrZXJRdWV1ZT1uZXcgQXJyYXkodCksdGhpcy53b3JrZXJRdWV1ZS5maWxsKG51bGwpLHRoaXMucnVuSW5mbz1bXX1ydW5UYXNrcyh0LGU9bnVsbCl7bGV0IHI9e3Rhc2tRdWV1ZTpbXSxyZXN1bHRzOltdLGFkZGluZ1Rhc2tzOiExLHBvc3Rwb25lZDohMSxydW5uaW5nV29ya2VyczowLGluZGV4OjAsY29tcGxldGVkVGFza3M6MCxwcm9ncmVzc0NhbGxiYWNrOmUsY2FuY2VsZWQ6ITF9O3JldHVybiB0aGlzLnJ1bkluZm8ucHVzaChyKSxyLmluZGV4PXRoaXMucnVuSW5mby5sZW5ndGgtMSx7cHJvbWlzZTpuZXcgUHJvbWlzZSgobixhKT0+e3IucmVzb2x2ZT1uLHIucmVqZWN0PWEsci5yZXN1bHRzPW5ldyBBcnJheSh0Lmxlbmd0aCksci5jb21wbGV0ZWRUYXNrcz0wLHIuYWRkaW5nVGFza3M9ITAsdC5mb3JFYWNoKChpLGwpPT57dGhpcy5hZGRUYXNrKHIuaW5kZXgsbCxpKX0pLHIuYWRkaW5nVGFza3M9ITF9KSxydW5JZDpyLmluZGV4fX10ZXJtaW5hdGVXb3JrZXJzKCl7Zm9yKGxldCB0PTA7dDx0aGlzLndvcmtlclF1ZXVlLmxlbmd0aDt0Kyspe2xldCBlPXRoaXMud29ya2VyUXVldWVbdF07ZT8udGVybWluYXRlKCksdGhpcy53b3JrZXJRdWV1ZVt0XT1udWxsfX1jYW5jZWwodCl7bGV0IGU9dGhpcy5ydW5JbmZvW3RdO2UhPW51bGwmJihlLmNhbmNlbGVkPSEwKX1hZGRUYXNrKHQsZSxyKXtsZXQgbj10aGlzLnJ1bkluZm9bdF07aWYobj8uY2FuY2VsZWQ9PT0hMCl7bi5yZWplY3QoIlJlbWFpbmluZyB0YXNrcyBjYW5jZWxlZCIpLHRoaXMuY2xlYXJUYXNrKG4uaW5kZXgpO3JldHVybn1pZih0aGlzLndvcmtlclF1ZXVlLmxlbmd0aD4wKXtsZXQgYT10aGlzLndvcmtlclF1ZXVlLnBvcCgpO24ucnVubmluZ1dvcmtlcnMrKyx0aGlzLmZjbihhLC4uLnIpLnRoZW4oaT0+e3Zhcnt3ZWJXb3JrZXI6bH09aSx1PWJ0KGksWyJ3ZWJXb3JrZXIiXSk7aWYodGhpcy53b3JrZXJRdWV1ZS5wdXNoKGwpLHRoaXMucnVuSW5mb1t0XSE9PW51bGwpe2lmKG4ucnVubmluZ1dvcmtlcnMtLSxuLnJlc3VsdHNbZV09dSxuLmNvbXBsZXRlZFRhc2tzKyssbi5wcm9ncmVzc0NhbGxiYWNrIT1udWxsJiZuLnByb2dyZXNzQ2FsbGJhY2sobi5jb21wbGV0ZWRUYXNrcyxuLnJlc3VsdHMubGVuZ3RoKSxuLnRhc2tRdWV1ZS5sZW5ndGg+MCl7bGV0IG89bi50YXNrUXVldWUuc2hpZnQoKTt0aGlzLmFkZFRhc2sodCxvWzBdLG9bMV0pfWVsc2UgaWYoIW4uYWRkaW5nVGFza3MmJm4ucnVubmluZ1dvcmtlcnM9PT0wKXtsZXQgbz1uLnJlc3VsdHM7bi5yZXNvbHZlKG8pLHRoaXMuY2xlYXJUYXNrKG4uaW5kZXgpfX19KS5jYXRjaChpPT57bi5yZWplY3QoaSksdGhpcy5jbGVhclRhc2sobi5pbmRleCl9KX1lbHNlIG4ucnVubmluZ1dvcmtlcnMhPT0wfHxuLnBvc3Rwb25lZD9uLnRhc2tRdWV1ZS5wdXNoKFtlLHJdKToobi5wb3N0cG9uZWQ9ITAsc2V0VGltZW91dCgoKT0+e24ucG9zdHBvbmVkPSExLHRoaXMuYWRkVGFzayhuLmluZGV4LGUscil9LDUwKSl9Y2xlYXJUYXNrKHQpe3RoaXMucnVuSW5mb1t0XS5yZXN1bHRzPVtdLHRoaXMucnVuSW5mb1t0XS50YXNrUXVldWU9W10sdGhpcy5ydW5JbmZvW3RdLnByb2dyZXNzQ2FsbGJhY2s9bnVsbCx0aGlzLnJ1bkluZm9bdF0uY2FuY2VsZWQ9bnVsbCx0aGlzLnJ1bkluZm9bdF0ucmVqZWN0PSgpPT57fSx0aGlzLnJ1bkluZm9bdF0ucmVzb2x2ZT0oKT0+e319fSxOQT1VQTt2YXIgRnQ9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIGt0KEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IHQ9W107Zm9yKGxldCBlPTA7ZTxBLmxlbmd0aDtlKyspe2xldCByPVJ0KEFbZV0pO3IhPT1udWxsJiZ0LnB1c2gocil9cmV0dXJuIHR9ZnVuY3Rpb24gUnQoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgdD1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD90PUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKHQ9QSksRnQmJnQgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOnR9dmFyIGNlPWt0O2Z1bmN0aW9uICQoQSx0KXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseSh0LGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzpVdH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6R0F9PU9iamVjdCxJQT0oQT0+dD0+e2xldCBlPVV0LmNhbGwodCk7cmV0dXJuIEFbZV18fChBW2VdPWUuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxHPUE9PihBPUEudG9Mb3dlckNhc2UoKSx0PT5JQSh0KT09PUEpLGdBPUE9PnQ9PnR5cGVvZiB0PT09QSx7aXNBcnJheTpLfT1BcnJheSxBQT1nQSgidW5kZWZpbmVkIik7ZnVuY3Rpb24gTnQoQSl7cmV0dXJuIEEhPT1udWxsJiYhQUEoQSkmJkEuY29uc3RydWN0b3IhPT1udWxsJiYhQUEoQS5jb25zdHJ1Y3RvcikmJk4oQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIENlPUcoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gT3QoQSl7bGV0IHQ7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz90PUFycmF5QnVmZmVyLmlzVmlldyhBKTp0PUEmJkEuYnVmZmVyJiZDZShBLmJ1ZmZlciksdH12YXIgVHQ9Z0EoInN0cmluZyIpLE49Z0EoImZ1bmN0aW9uIiksQmU9Z0EoIm51bWJlciIpLGxBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsR3Q9QT0+QT09PSEwfHxBPT09ITEsc0E9QT0+e2lmKElBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IHQ9R0EoQSk7cmV0dXJuKHQ9PT1udWxsfHx0PT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKHQpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0seHQ9RygiRGF0ZSIpLEx0PUcoIkZpbGUiKSxQdD1HKCJCbG9iIiksTXQ9RygiRmlsZUxpc3QiKSxKdD1BPT5sQShBKSYmTihBLnBpcGUpLEh0PUE9PntsZXQgdDtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxOKEEuYXBwZW5kKSYmKCh0PUlBKEEpKT09PSJmb3JtZGF0YSJ8fHQ9PT0ib2JqZWN0IiYmTihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxZdD1HKCJVUkxTZWFyY2hQYXJhbXMiKSxxdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xzXHVGRUZGXHhBMF0rfFtcc1x1RkVGRlx4QTBdKyQvZywiIik7ZnVuY3Rpb24gZUEoQSx0LHthbGxPd25LZXlzOmU9ITF9PXt9KXtpZihBPT09bnVsbHx8dHlwZW9mIEE+InUiKXJldHVybjtsZXQgcixuO2lmKHR5cGVvZiBBIT0ib2JqZWN0IiYmKEE9W0FdKSxLKEEpKWZvcihyPTAsbj1BLmxlbmd0aDtyPG47cisrKXQuY2FsbChudWxsLEFbcl0scixBKTtlbHNle2xldCBhPWU/T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSk6T2JqZWN0LmtleXMoQSksaT1hLmxlbmd0aCxsO2ZvcihyPTA7cjxpO3IrKylsPWFbcl0sdC5jYWxsKG51bGwsQVtsXSxsLEEpfX1mdW5jdGlvbiBFZShBLHQpe3Q9dC50b0xvd2VyQ2FzZSgpO2xldCBlPU9iamVjdC5rZXlzKEEpLHI9ZS5sZW5ndGgsbjtmb3IoO3ItLSA+MDspaWYobj1lW3JdLHQ9PT1uLnRvTG93ZXJDYXNlKCkpcmV0dXJuIG47cmV0dXJuIG51bGx9dmFyIGRlPSgoKT0+dHlwZW9mIGdsb2JhbFRoaXM8InUiP2dsb2JhbFRoaXM6dHlwZW9mIHNlbGY8InUiP3NlbGY6dHlwZW9mIHdpbmRvdzwidSI/d2luZG93Omdsb2JhbCkoKSxRZT1BPT4hQUEoQSkmJkEhPT1kZTtmdW5jdGlvbiBUQSgpe2xldHtjYXNlbGVzczpBfT1RZSh0aGlzKSYmdGhpc3x8e30sdD17fSxlPShyLG4pPT57bGV0IGE9QSYmRWUodCxuKXx8bjtzQSh0W2FdKSYmc0Eocik/dFthXT1UQSh0W2FdLHIpOnNBKHIpP3RbYV09VEEoe30scik6SyhyKT90W2FdPXIuc2xpY2UoKTp0W2FdPXJ9O2ZvcihsZXQgcj0wLG49YXJndW1lbnRzLmxlbmd0aDtyPG47cisrKWFyZ3VtZW50c1tyXSYmZUEoYXJndW1lbnRzW3JdLGUpO3JldHVybiB0fXZhciB2dD0oQSx0LGUse2FsbE93bktleXM6cn09e30pPT4oZUEodCwobixhKT0+e2UmJk4obik/QVthXT0kKG4sZSk6QVthXT1ufSx7YWxsT3duS2V5czpyfSksQSksS3Q9QT0+KEEuY2hhckNvZGVBdCgwKT09PTY1Mjc5JiYoQT1BLnNsaWNlKDEpKSxBKSxXdD0oQSx0LGUscik9PntBLnByb3RvdHlwZT1PYmplY3QuY3JlYXRlKHQucHJvdG90eXBlLHIpLEEucHJvdG90eXBlLmNvbnN0cnVjdG9yPUEsT2JqZWN0LmRlZmluZVByb3BlcnR5KEEsInN1cGVyIix7dmFsdWU6dC5wcm90b3R5cGV9KSxlJiZPYmplY3QuYXNzaWduKEEucHJvdG90eXBlLGUpfSxqdD0oQSx0LGUscik9PntsZXQgbixhLGksbD17fTtpZih0PXR8fHt9LEE9PW51bGwpcmV0dXJuIHQ7ZG97Zm9yKG49T2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMoQSksYT1uLmxlbmd0aDthLS0gPjA7KWk9blthXSwoIXJ8fHIoaSxBLHQpKSYmIWxbaV0mJih0W2ldPUFbaV0sbFtpXT0hMCk7QT1lIT09ITEmJkdBKEEpfXdoaWxlKEEmJighZXx8ZShBLHQpKSYmQSE9PU9iamVjdC5wcm90b3R5cGUpO3JldHVybiB0fSxfdD0oQSx0LGUpPT57QT1TdHJpbmcoQSksKGU9PT12b2lkIDB8fGU+QS5sZW5ndGgpJiYoZT1BLmxlbmd0aCksZS09dC5sZW5ndGg7bGV0IHI9QS5pbmRleE9mKHQsZSk7cmV0dXJuIHIhPT0tMSYmcj09PWV9LHp0PUE9PntpZighQSlyZXR1cm4gbnVsbDtpZihLKEEpKXJldHVybiBBO2xldCB0PUEubGVuZ3RoO2lmKCFCZSh0KSlyZXR1cm4gbnVsbDtsZXQgZT1uZXcgQXJyYXkodCk7Zm9yKDt0LS0gPjA7KWVbdF09QVt0XTtyZXR1cm4gZX0sVnQ9KEE9PnQ9PkEmJnQgaW5zdGFuY2VvZiBBKSh0eXBlb2YgVWludDhBcnJheTwidSImJkdBKFVpbnQ4QXJyYXkpKSxadD0oQSx0KT0+e2xldCByPShBJiZBW1N5bWJvbC5pdGVyYXRvcl0pLmNhbGwoQSksbjtmb3IoOyhuPXIubmV4dCgpKSYmIW4uZG9uZTspe2xldCBhPW4udmFsdWU7dC5jYWxsKEEsYVswXSxhWzFdKX19LFh0PShBLHQpPT57bGV0IGUscj1bXTtmb3IoOyhlPUEuZXhlYyh0KSkhPT1udWxsOylyLnB1c2goZSk7cmV0dXJuIHJ9LCR0PUcoIkhUTUxGb3JtRWxlbWVudCIpLEFyPUE9PkEudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC9bLV9cc10oW2EtelxkXSkoXHcqKS9nLGZ1bmN0aW9uKGUscixuKXtyZXR1cm4gci50b1VwcGVyQ2FzZSgpK259KSxmZT0oKHtoYXNPd25Qcm9wZXJ0eTpBfSk9Pih0LGUpPT5BLmNhbGwodCxlKSkoT2JqZWN0LnByb3RvdHlwZSksZXI9RygiUmVnRXhwIikscGU9KEEsdCk9PntsZXQgZT1PYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyhBKSxyPXt9O2VBKGUsKG4sYSk9Pnt0KG4sYSxBKSE9PSExJiYoclthXT1uKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKEEscil9LHRyPUE9PntwZShBLCh0LGUpPT57aWYoTihBKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKGUpIT09LTEpcmV0dXJuITE7bGV0IHI9QVtlXTtpZihOKHIpKXtpZih0LmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIHQpe3Qud3JpdGFibGU9ITE7cmV0dXJufXQuc2V0fHwodC5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgJyIrZSsiJyIpfSl9fSl9LHJyPShBLHQpPT57bGV0IGU9e30scj1uPT57bi5mb3JFYWNoKGE9PntlW2FdPSEwfSl9O3JldHVybiBLKEEpP3IoQSk6cihTdHJpbmcoQSkuc3BsaXQodCkpLGV9LG5yPSgpPT57fSxpcj0oQSx0KT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6dCksT0E9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iix1ZT0iMDEyMzQ1Njc4OSIsbWU9e0RJR0lUOnVlLEFMUEhBOk9BLEFMUEhBX0RJR0lUOk9BK09BLnRvVXBwZXJDYXNlKCkrdWV9LGFyPShBPTE2LHQ9bWUuQUxQSEFfRElHSVQpPT57bGV0IGU9IiIse2xlbmd0aDpyfT10O2Zvcig7QS0tOyllKz10W01hdGgucmFuZG9tKCkqcnwwXTtyZXR1cm4gZX07ZnVuY3Rpb24gb3IoQSl7cmV0dXJuISEoQSYmTihBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIHNyPUE9PntsZXQgdD1uZXcgQXJyYXkoMTApLGU9KHIsbik9PntpZihsQShyKSl7aWYodC5pbmRleE9mKHIpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gcikpe3Rbbl09cjtsZXQgYT1LKHIpP1tdOnt9O3JldHVybiBlQShyLChpLGwpPT57bGV0IHU9ZShpLG4rMSk7IUFBKHUpJiYoYVtsXT11KX0pLHRbbl09dm9pZCAwLGF9fXJldHVybiByfTtyZXR1cm4gZShBLDApfSxJcj1HKCJBc3luY0Z1bmN0aW9uIiksZ3I9QT0+QSYmKGxBKEEpfHxOKEEpKSYmTihBLnRoZW4pJiZOKEEuY2F0Y2gpLGc9e2lzQXJyYXk6Syxpc0FycmF5QnVmZmVyOkNlLGlzQnVmZmVyOk50LGlzRm9ybURhdGE6SHQsaXNBcnJheUJ1ZmZlclZpZXc6T3QsaXNTdHJpbmc6VHQsaXNOdW1iZXI6QmUsaXNCb29sZWFuOkd0LGlzT2JqZWN0OmxBLGlzUGxhaW5PYmplY3Q6c0EsaXNVbmRlZmluZWQ6QUEsaXNEYXRlOnh0LGlzRmlsZTpMdCxpc0Jsb2I6UHQsaXNSZWdFeHA6ZXIsaXNGdW5jdGlvbjpOLGlzU3RyZWFtOkp0LGlzVVJMU2VhcmNoUGFyYW1zOll0LGlzVHlwZWRBcnJheTpWdCxpc0ZpbGVMaXN0Ok10LGZvckVhY2g6ZUEsbWVyZ2U6VEEsZXh0ZW5kOnZ0LHRyaW06cXQsc3RyaXBCT006S3QsaW5oZXJpdHM6V3QsdG9GbGF0T2JqZWN0Omp0LGtpbmRPZjpJQSxraW5kT2ZUZXN0OkcsZW5kc1dpdGg6X3QsdG9BcnJheTp6dCxmb3JFYWNoRW50cnk6WnQsbWF0Y2hBbGw6WHQsaXNIVE1MRm9ybTokdCxoYXNPd25Qcm9wZXJ0eTpmZSxoYXNPd25Qcm9wOmZlLHJlZHVjZURlc2NyaXB0b3JzOnBlLGZyZWV6ZU1ldGhvZHM6dHIsdG9PYmplY3RTZXQ6cnIsdG9DYW1lbENhc2U6QXIsbm9vcDpucix0b0Zpbml0ZU51bWJlcjppcixmaW5kS2V5OkVlLGdsb2JhbDpkZSxpc0NvbnRleHREZWZpbmVkOlFlLEFMUEhBQkVUOm1lLGdlbmVyYXRlU3RyaW5nOmFyLGlzU3BlY0NvbXBsaWFudEZvcm06b3IsdG9KU09OT2JqZWN0OnNyLGlzQXN5bmNGbjpJcixpc1RoZW5hYmxlOmdyfTtmdW5jdGlvbiBXKEEsdCxlLHIsbil7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPUEsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIix0JiYodGhpcy5jb2RlPXQpLGUmJih0aGlzLmNvbmZpZz1lKSxyJiYodGhpcy5yZXF1ZXN0PXIpLG4mJih0aGlzLnJlc3BvbnNlPW4pfWcuaW5oZXJpdHMoVyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOmcudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIGhlPVcucHJvdG90eXBlLHllPXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goQT0+e3llW0FdPXt2YWx1ZTpBfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKFcseWUpO09iamVjdC5kZWZpbmVQcm9wZXJ0eShoZSwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtXLmZyb209KEEsdCxlLHIsbixhKT0+e2xldCBpPU9iamVjdC5jcmVhdGUoaGUpO3JldHVybiBnLnRvRmxhdE9iamVjdChBLGksZnVuY3Rpb24odSl7cmV0dXJuIHUhPT1FcnJvci5wcm90b3R5cGV9LGw9PmwhPT0iaXNBeGlvc0Vycm9yIiksVy5jYWxsKGksQS5tZXNzYWdlLHQsZSxyLG4pLGkuY2F1c2U9QSxpLm5hbWU9QS5uYW1lLGEmJk9iamVjdC5hc3NpZ24oaSxhKSxpfTt2YXIgZD1XO3ZhciBjQT1udWxsO2Z1bmN0aW9uIHhBKEEpe3JldHVybiBnLmlzUGxhaW5PYmplY3QoQSl8fGcuaXNBcnJheShBKX1mdW5jdGlvbiBEZShBKXtyZXR1cm4gZy5lbmRzV2l0aChBLCJbXSIpP0Euc2xpY2UoMCwtMik6QX1mdW5jdGlvbiB3ZShBLHQsZSl7cmV0dXJuIEE/QS5jb25jYXQodCkubWFwKGZ1bmN0aW9uKG4sYSl7cmV0dXJuIG49RGUobiksIWUmJmE/IlsiK24rIl0iOm59KS5qb2luKGU/Ii4iOiIiKTp0fWZ1bmN0aW9uIGxyKEEpe3JldHVybiBnLmlzQXJyYXkoQSkmJiFBLnNvbWUoeEEpfXZhciBjcj1nLnRvRmxhdE9iamVjdChnLHt9LG51bGwsZnVuY3Rpb24odCl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KHQpfSk7ZnVuY3Rpb24gZnIoQSx0LGUpe2lmKCFnLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO3Q9dHx8bmV3KGNBfHxGb3JtRGF0YSksZT1nLnRvRmxhdE9iamVjdChlLHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oQixwKXtyZXR1cm4hZy5pc1VuZGVmaW5lZChwW0JdKX0pO2xldCByPWUubWV0YVRva2VucyxuPWUudmlzaXRvcnx8cyxhPWUuZG90cyxpPWUuaW5kZXhlcyx1PShlLkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJmcuaXNTcGVjQ29tcGxpYW50Rm9ybSh0KTtpZighZy5pc0Z1bmN0aW9uKG4pKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gbyhmKXtpZihmPT09bnVsbClyZXR1cm4iIjtpZihnLmlzRGF0ZShmKSlyZXR1cm4gZi50b0lTT1N0cmluZygpO2lmKCF1JiZnLmlzQmxvYihmKSl0aHJvdyBuZXcgZCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gZy5pc0FycmF5QnVmZmVyKGYpfHxnLmlzVHlwZWRBcnJheShmKT91JiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbZl0pOkJ1ZmZlci5mcm9tKGYpOmZ9ZnVuY3Rpb24gcyhmLEIscCl7bGV0IG09ZjtpZihmJiYhcCYmdHlwZW9mIGY9PSJvYmplY3QiKXtpZihnLmVuZHNXaXRoKEIsInt9IikpQj1yP0I6Qi5zbGljZSgwLC0yKSxmPUpTT04uc3RyaW5naWZ5KGYpO2Vsc2UgaWYoZy5pc0FycmF5KGYpJiZscihmKXx8KGcuaXNGaWxlTGlzdChmKXx8Zy5lbmRzV2l0aChCLCJbXSIpKSYmKG09Zy50b0FycmF5KGYpKSlyZXR1cm4gQj1EZShCKSxtLmZvckVhY2goZnVuY3Rpb24oaCxiQSl7IShnLmlzVW5kZWZpbmVkKGgpfHxoPT09bnVsbCkmJnQuYXBwZW5kKGk9PT0hMD93ZShbQl0sYkEsYSk6aT09PW51bGw/QjpCKyJbXSIsbyhoKSl9KSwhMX1yZXR1cm4geEEoZik/ITA6KHQuYXBwZW5kKHdlKHAsQixhKSxvKGYpKSwhMSl9bGV0IEM9W10sYz1PYmplY3QuYXNzaWduKGNyLHtkZWZhdWx0VmlzaXRvcjpzLGNvbnZlcnRWYWx1ZTpvLGlzVmlzaXRhYmxlOnhBfSk7ZnVuY3Rpb24gSShmLEIpe2lmKCFnLmlzVW5kZWZpbmVkKGYpKXtpZihDLmluZGV4T2YoZikhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrQi5qb2luKCIuIikpO0MucHVzaChmKSxnLmZvckVhY2goZixmdW5jdGlvbihtLFEpeyghKGcuaXNVbmRlZmluZWQobSl8fG09PT1udWxsKSYmbi5jYWxsKHQsbSxnLmlzU3RyaW5nKFEpP1EudHJpbSgpOlEsQixjKSk9PT0hMCYmSShtLEI/Qi5jb25jYXQoUSk6W1FdKX0pLEMucG9wKCl9fWlmKCFnLmlzT2JqZWN0KEEpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gSShBKSx0fXZhciBMPWZyO2Z1bmN0aW9uIFNlKEEpe2xldCB0PXsiISI6IiUyMSIsIiciOiIlMjciLCIoIjoiJTI4IiwiKSI6IiUyOSIsIn4iOiIlN0UiLCIlMjAiOiIrIiwiJTAwIjoiXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shJygpfl18JTIwfCUwMC9nLGZ1bmN0aW9uKHIpe3JldHVybiB0W3JdfSl9ZnVuY3Rpb24gYmUoQSx0KXt0aGlzLl9wYWlycz1bXSxBJiZMKEEsdGhpcyx0KX12YXIgRmU9YmUucHJvdG90eXBlO0ZlLmFwcGVuZD1mdW5jdGlvbih0LGUpe3RoaXMuX3BhaXJzLnB1c2goW3QsZV0pfTtGZS50b1N0cmluZz1mdW5jdGlvbih0KXtsZXQgZT10P2Z1bmN0aW9uKHIpe3JldHVybiB0LmNhbGwodGhpcyxyLFNlKX06U2U7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihuKXtyZXR1cm4gZShuWzBdKSsiPSIrZShuWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIGZBPWJlO2Z1bmN0aW9uIHVyKEEpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoQSkucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfWZ1bmN0aW9uIHRBKEEsdCxlKXtpZighdClyZXR1cm4gQTtsZXQgcj1lJiZlLmVuY29kZXx8dXIsbj1lJiZlLnNlcmlhbGl6ZSxhO2lmKG4/YT1uKHQsZSk6YT1nLmlzVVJMU2VhcmNoUGFyYW1zKHQpP3QudG9TdHJpbmcoKTpuZXcgZkEodCxlKS50b1N0cmluZyhyKSxhKXtsZXQgaT1BLmluZGV4T2YoIiMiKTtpIT09LTEmJihBPUEuc2xpY2UoMCxpKSksQSs9KEEuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikrYX1yZXR1cm4gQX12YXIgTEE9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZSh0LGUscil7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOnQscmVqZWN0ZWQ6ZSxzeW5jaHJvbm91czpyP3Iuc3luY2hyb25vdXM6ITEscnVuV2hlbjpyP3IucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdCh0KXt0aGlzLmhhbmRsZXJzW3RdJiYodGhpcy5oYW5kbGVyc1t0XT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKHQpe2cuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHIpe3IhPT1udWxsJiZ0KHIpfSl9fSxQQT1MQTt2YXIgdUE9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9O3ZhciBrZT10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6ZkE7dmFyIFJlPXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgVWU9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgQ3I9KCgpPT57bGV0IEE7cmV0dXJuIHR5cGVvZiBuYXZpZ2F0b3I8InUiJiYoKEE9bmF2aWdhdG9yLnByb2R1Y3QpPT09IlJlYWN0TmF0aXZlInx8QT09PSJOYXRpdmVTY3JpcHQifHxBPT09Ik5TIik/ITE6dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSJ9KSgpLEJyPSgoKT0+dHlwZW9mIFdvcmtlckdsb2JhbFNjb3BlPCJ1IiYmc2VsZiBpbnN0YW5jZW9mIFdvcmtlckdsb2JhbFNjb3BlJiZ0eXBlb2Ygc2VsZi5pbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKSgpLFM9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6a2UsRm9ybURhdGE6UmUsQmxvYjpVZX0saXNTdGFuZGFyZEJyb3dzZXJFbnY6Q3IsaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6QnIscHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O2Z1bmN0aW9uIE1BKEEsdCl7cmV0dXJuIEwoQSxuZXcgUy5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKGUscixuLGEpe3JldHVybiBTLmlzTm9kZSYmZy5pc0J1ZmZlcihlKT8odGhpcy5hcHBlbmQocixlLnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOmEuZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sdCkpfWZ1bmN0aW9uIEVyKEEpe3JldHVybiBnLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxBKS5tYXAodD0+dFswXT09PSJbXSI/IiI6dFsxXXx8dFswXSl9ZnVuY3Rpb24gZHIoQSl7bGV0IHQ9e30sZT1PYmplY3Qua2V5cyhBKSxyLG49ZS5sZW5ndGgsYTtmb3Iocj0wO3I8bjtyKyspYT1lW3JdLHRbYV09QVthXTtyZXR1cm4gdH1mdW5jdGlvbiBRcihBKXtmdW5jdGlvbiB0KGUscixuLGEpe2xldCBpPWVbYSsrXSxsPU51bWJlci5pc0Zpbml0ZSgraSksdT1hPj1lLmxlbmd0aDtyZXR1cm4gaT0haSYmZy5pc0FycmF5KG4pP24ubGVuZ3RoOmksdT8oZy5oYXNPd25Qcm9wKG4saSk/bltpXT1bbltpXSxyXTpuW2ldPXIsIWwpOigoIW5baV18fCFnLmlzT2JqZWN0KG5baV0pKSYmKG5baV09W10pLHQoZSxyLG5baV0sYSkmJmcuaXNBcnJheShuW2ldKSYmKG5baV09ZHIobltpXSkpLCFsKX1pZihnLmlzRm9ybURhdGEoQSkmJmcuaXNGdW5jdGlvbihBLmVudHJpZXMpKXtsZXQgZT17fTtyZXR1cm4gZy5mb3JFYWNoRW50cnkoQSwocixuKT0+e3QoRXIociksbixlLDApfSksZX1yZXR1cm4gbnVsbH12YXIgQ0E9UXI7dmFyIHByPXsiQ29udGVudC1UeXBlIjp2b2lkIDB9O2Z1bmN0aW9uIG1yKEEsdCxlKXtpZihnLmlzU3RyaW5nKEEpKXRyeXtyZXR1cm4odHx8SlNPTi5wYXJzZSkoQSksZy50cmltKEEpfWNhdGNoKHIpe2lmKHIubmFtZSE9PSJTeW50YXhFcnJvciIpdGhyb3cgcn1yZXR1cm4oZXx8SlNPTi5zdHJpbmdpZnkpKEEpfXZhciBCQT17dHJhbnNpdGlvbmFsOnVBLGFkYXB0ZXI6WyJ4aHIiLCJodHRwIl0sdHJhbnNmb3JtUmVxdWVzdDpbZnVuY3Rpb24odCxlKXtsZXQgcj1lLmdldENvbnRlbnRUeXBlKCl8fCIiLG49ci5pbmRleE9mKCJhcHBsaWNhdGlvbi9qc29uIik+LTEsYT1nLmlzT2JqZWN0KHQpO2lmKGEmJmcuaXNIVE1MRm9ybSh0KSYmKHQ9bmV3IEZvcm1EYXRhKHQpKSxnLmlzRm9ybURhdGEodCkpcmV0dXJuIG4mJm4/SlNPTi5zdHJpbmdpZnkoQ0EodCkpOnQ7aWYoZy5pc0FycmF5QnVmZmVyKHQpfHxnLmlzQnVmZmVyKHQpfHxnLmlzU3RyZWFtKHQpfHxnLmlzRmlsZSh0KXx8Zy5pc0Jsb2IodCkpcmV0dXJuIHQ7aWYoZy5pc0FycmF5QnVmZmVyVmlldyh0KSlyZXR1cm4gdC5idWZmZXI7aWYoZy5pc1VSTFNlYXJjaFBhcmFtcyh0KSlyZXR1cm4gZS5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkO2NoYXJzZXQ9dXRmLTgiLCExKSx0LnRvU3RyaW5nKCk7bGV0IGw7aWYoYSl7aWYoci5pbmRleE9mKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiKT4tMSlyZXR1cm4gTUEodCx0aGlzLmZvcm1TZXJpYWxpemVyKS50b1N0cmluZygpO2lmKChsPWcuaXNGaWxlTGlzdCh0KSl8fHIuaW5kZXhPZigibXVsdGlwYXJ0L2Zvcm0tZGF0YSIpPi0xKXtsZXQgdT10aGlzLmVudiYmdGhpcy5lbnYuRm9ybURhdGE7cmV0dXJuIEwobD97ImZpbGVzW10iOnR9OnQsdSYmbmV3IHUsdGhpcy5mb3JtU2VyaWFsaXplcil9fXJldHVybiBhfHxuPyhlLnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi9qc29uIiwhMSksbXIodCkpOnR9XSx0cmFuc2Zvcm1SZXNwb25zZTpbZnVuY3Rpb24odCl7bGV0IGU9dGhpcy50cmFuc2l0aW9uYWx8fEJBLnRyYW5zaXRpb25hbCxyPWUmJmUuZm9yY2VkSlNPTlBhcnNpbmcsbj10aGlzLnJlc3BvbnNlVHlwZT09PSJqc29uIjtpZih0JiZnLmlzU3RyaW5nKHQpJiYociYmIXRoaXMucmVzcG9uc2VUeXBlfHxuKSl7bGV0IGk9IShlJiZlLnNpbGVudEpTT05QYXJzaW5nKSYmbjt0cnl7cmV0dXJuIEpTT04ucGFyc2UodCl9Y2F0Y2gobCl7aWYoaSl0aHJvdyBsLm5hbWU9PT0iU3ludGF4RXJyb3IiP2QuZnJvbShsLGQuRVJSX0JBRF9SRVNQT05TRSx0aGlzLG51bGwsdGhpcy5yZXNwb25zZSk6bH19cmV0dXJuIHR9XSx0aW1lb3V0OjAseHNyZkNvb2tpZU5hbWU6IlhTUkYtVE9LRU4iLHhzcmZIZWFkZXJOYW1lOiJYLVhTUkYtVE9LRU4iLG1heENvbnRlbnRMZW5ndGg6LTEsbWF4Qm9keUxlbmd0aDotMSxlbnY6e0Zvcm1EYXRhOlMuY2xhc3Nlcy5Gb3JtRGF0YSxCbG9iOlMuY2xhc3Nlcy5CbG9ifSx2YWxpZGF0ZVN0YXR1czpmdW5jdGlvbih0KXtyZXR1cm4gdD49MjAwJiZ0PDMwMH0saGVhZGVyczp7Y29tbW9uOntBY2NlcHQ6ImFwcGxpY2F0aW9uL2pzb24sIHRleHQvcGxhaW4sICovKiJ9fX07Zy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCJdLGZ1bmN0aW9uKHQpe0JBLmhlYWRlcnNbdF09e319KTtnLmZvckVhY2goWyJwb3N0IiwicHV0IiwicGF0Y2giXSxmdW5jdGlvbih0KXtCQS5oZWFkZXJzW3RdPWcubWVyZ2UocHIpfSk7dmFyIGo9QkE7dmFyIGhyPWcudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksTmU9QT0+e2xldCB0PXt9LGUscixuO3JldHVybiBBJiZBLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihpKXtuPWkuaW5kZXhPZigiOiIpLGU9aS5zdWJzdHJpbmcoMCxuKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPWkuc3Vic3RyaW5nKG4rMSkudHJpbSgpLCEoIWV8fHRbZV0mJmhyW2VdKSYmKGU9PT0ic2V0LWNvb2tpZSI/dFtlXT90W2VdLnB1c2gocik6dFtlXT1bcl06dFtlXT10W2VdP3RbZV0rIiwgIityOnIpfSksdH07dmFyIE9lPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gckEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBFQShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6Zy5pc0FycmF5KEEpP0EubWFwKEVBKTpTdHJpbmcoQSl9ZnVuY3Rpb24geXIoQSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKSxlPS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9ZS5leGVjKEEpOyl0W3JbMV1dPXJbMl07cmV0dXJuIHR9dmFyIHdyPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIEpBKEEsdCxlLHIsbil7aWYoZy5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyx0LGUpO2lmKG4mJih0PWUpLCEhZy5pc1N0cmluZyh0KSl7aWYoZy5pc1N0cmluZyhyKSlyZXR1cm4gdC5pbmRleE9mKHIpIT09LTE7aWYoZy5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KHQpfX1mdW5jdGlvbiBEcihBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLCh0LGUscik9PmUudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBTcihBLHQpe2xldCBlPWcudG9DYW1lbENhc2UoIiAiK3QpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KEEscitlLHt2YWx1ZTpmdW5jdGlvbihuLGEsaSl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLHQsbixhLGkpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBfPWNsYXNze2NvbnN0cnVjdG9yKHQpe3QmJnRoaXMuc2V0KHQpfXNldCh0LGUscil7bGV0IG49dGhpcztmdW5jdGlvbiBhKGwsdSxvKXtsZXQgcz1yQSh1KTtpZighcyl0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IEM9Zy5maW5kS2V5KG4scyk7KCFDfHxuW0NdPT09dm9pZCAwfHxvPT09ITB8fG89PT12b2lkIDAmJm5bQ10hPT0hMSkmJihuW0N8fHVdPUVBKGwpKX1sZXQgaT0obCx1KT0+Zy5mb3JFYWNoKGwsKG8scyk9PmEobyxzLHUpKTtyZXR1cm4gZy5pc1BsYWluT2JqZWN0KHQpfHx0IGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9pKHQsZSk6Zy5pc1N0cmluZyh0KSYmKHQ9dC50cmltKCkpJiYhd3IodCk/aShOZSh0KSxlKTp0IT1udWxsJiZhKGUsdCxyKSx0aGlzfWdldCh0LGUpe2lmKHQ9ckEodCksdCl7bGV0IHI9Zy5maW5kS2V5KHRoaXMsdCk7aWYocil7bGV0IG49dGhpc1tyXTtpZighZSlyZXR1cm4gbjtpZihlPT09ITApcmV0dXJuIHlyKG4pO2lmKGcuaXNGdW5jdGlvbihlKSlyZXR1cm4gZS5jYWxsKHRoaXMsbixyKTtpZihnLmlzUmVnRXhwKGUpKXJldHVybiBlLmV4ZWMobik7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyh0LGUpe2lmKHQ9ckEodCksdCl7bGV0IHI9Zy5maW5kS2V5KHRoaXMsdCk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCFlfHxKQSh0aGlzLHRoaXNbcl0scixlKSkpfXJldHVybiExfWRlbGV0ZSh0LGUpe2xldCByPXRoaXMsbj0hMTtmdW5jdGlvbiBhKGkpe2lmKGk9ckEoaSksaSl7bGV0IGw9Zy5maW5kS2V5KHIsaSk7bCYmKCFlfHxKQShyLHJbbF0sbCxlKSkmJihkZWxldGUgcltsXSxuPSEwKX19cmV0dXJuIGcuaXNBcnJheSh0KT90LmZvckVhY2goYSk6YSh0KSxufWNsZWFyKHQpe2xldCBlPU9iamVjdC5rZXlzKHRoaXMpLHI9ZS5sZW5ndGgsbj0hMTtmb3IoO3ItLTspe2xldCBhPWVbcl07KCF0fHxKQSh0aGlzLHRoaXNbYV0sYSx0LCEwKSkmJihkZWxldGUgdGhpc1thXSxuPSEwKX1yZXR1cm4gbn1ub3JtYWxpemUodCl7bGV0IGU9dGhpcyxyPXt9O3JldHVybiBnLmZvckVhY2godGhpcywobixhKT0+e2xldCBpPWcuZmluZEtleShyLGEpO2lmKGkpe2VbaV09RUEobiksZGVsZXRlIGVbYV07cmV0dXJufWxldCBsPXQ/RHIoYSk6U3RyaW5nKGEpLnRyaW0oKTtsIT09YSYmZGVsZXRlIGVbYV0sZVtsXT1FQShuKSxyW2xdPSEwfSksdGhpc31jb25jYXQoLi4udCl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4udCl9dG9KU09OKHQpe2xldCBlPU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIGcuZm9yRWFjaCh0aGlzLChyLG4pPT57ciE9bnVsbCYmciE9PSExJiYoZVtuXT10JiZnLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksZX1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbdCxlXSk9PnQrIjogIitlKS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbSh0KXtyZXR1cm4gdCBpbnN0YW5jZW9mIHRoaXM/dDpuZXcgdGhpcyh0KX1zdGF0aWMgY29uY2F0KHQsLi4uZSl7bGV0IHI9bmV3IHRoaXModCk7cmV0dXJuIGUuZm9yRWFjaChuPT5yLnNldChuKSkscn1zdGF0aWMgYWNjZXNzb3IodCl7bGV0IHI9KHRoaXNbT2VdPXRoaXNbT2VdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsbj10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBhKGkpe2xldCBsPXJBKGkpO3JbbF18fChTcihuLGkpLHJbbF09ITApfXJldHVybiBnLmlzQXJyYXkodCk/dC5mb3JFYWNoKGEpOmEodCksdGhpc319O18uYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO2cuZnJlZXplTWV0aG9kcyhfLnByb3RvdHlwZSk7Zy5mcmVlemVNZXRob2RzKF8pO3ZhciBGPV87ZnVuY3Rpb24gbkEoQSx0KXtsZXQgZT10aGlzfHxqLHI9dHx8ZSxuPUYuZnJvbShyLmhlYWRlcnMpLGE9ci5kYXRhO3JldHVybiBnLmZvckVhY2goQSxmdW5jdGlvbihsKXthPWwuY2FsbChlLGEsbi5ub3JtYWxpemUoKSx0P3Quc3RhdHVzOnZvaWQgMCl9KSxuLm5vcm1hbGl6ZSgpLGF9ZnVuY3Rpb24gaUEoQSl7cmV0dXJuISEoQSYmQS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBUZShBLHQsZSl7ZC5jYWxsKHRoaXMsQT8/ImNhbmNlbGVkIixkLkVSUl9DQU5DRUxFRCx0LGUpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9Zy5pbmhlcml0cyhUZSxkLHtfX0NBTkNFTF9fOiEwfSk7dmFyIFA9VGU7ZnVuY3Rpb24gSEEoQSx0LGUpe2xldCByPWUuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyFlLnN0YXR1c3x8IXJ8fHIoZS5zdGF0dXMpP0EoZSk6dChuZXcgZCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK2Uuc3RhdHVzLFtkLkVSUl9CQURfUkVRVUVTVCxkLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IoZS5zdGF0dXMvMTAwKS00XSxlLmNvbmZpZyxlLnJlcXVlc3QsZSkpfXZhciBHZT1TLmlzU3RhbmRhcmRCcm93c2VyRW52P2Z1bmN0aW9uKCl7cmV0dXJue3dyaXRlOmZ1bmN0aW9uKGUscixuLGEsaSxsKXtsZXQgdT1bXTt1LnB1c2goZSsiPSIrZW5jb2RlVVJJQ29tcG9uZW50KHIpKSxnLmlzTnVtYmVyKG4pJiZ1LnB1c2goImV4cGlyZXM9IituZXcgRGF0ZShuKS50b0dNVFN0cmluZygpKSxnLmlzU3RyaW5nKGEpJiZ1LnB1c2goInBhdGg9IithKSxnLmlzU3RyaW5nKGkpJiZ1LnB1c2goImRvbWFpbj0iK2kpLGw9PT0hMCYmdS5wdXNoKCJzZWN1cmUiKSxkb2N1bWVudC5jb29raWU9dS5qb2luKCI7ICIpfSxyZWFkOmZ1bmN0aW9uKGUpe2xldCByPWRvY3VtZW50LmNvb2tpZS5tYXRjaChuZXcgUmVnRXhwKCIoXnw7XFxzKikoIitlKyIpPShbXjtdKikiKSk7cmV0dXJuIHI/ZGVjb2RlVVJJQ29tcG9uZW50KHJbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbihlKXt0aGlzLndyaXRlKGUsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBZQShBKXtyZXR1cm4vXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KEEpfWZ1bmN0aW9uIHFBKEEsdCl7cmV0dXJuIHQ/QS5yZXBsYWNlKC9cLyskLywiIikrIi8iK3QucmVwbGFjZSgvXlwvKy8sIiIpOkF9ZnVuY3Rpb24gYUEoQSx0KXtyZXR1cm4gQSYmIVlBKHQpP3FBKEEsdCk6dH12YXIgeGU9Uy5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCB0PS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksZT1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikscjtmdW5jdGlvbiBuKGEpe2xldCBpPWE7cmV0dXJuIHQmJihlLnNldEF0dHJpYnV0ZSgiaHJlZiIsaSksaT1lLmhyZWYpLGUuc2V0QXR0cmlidXRlKCJocmVmIixpKSx7aHJlZjplLmhyZWYscHJvdG9jb2w6ZS5wcm90b2NvbD9lLnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDplLmhvc3Qsc2VhcmNoOmUuc2VhcmNoP2Uuc2VhcmNoLnJlcGxhY2UoL15cPy8sIiIpOiIiLGhhc2g6ZS5oYXNoP2UuaGFzaC5yZXBsYWNlKC9eIy8sIiIpOiIiLGhvc3RuYW1lOmUuaG9zdG5hbWUscG9ydDplLnBvcnQscGF0aG5hbWU6ZS5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/ZS5wYXRobmFtZToiLyIrZS5wYXRobmFtZX19cmV0dXJuIHI9bih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oaSl7bGV0IGw9Zy5pc1N0cmluZyhpKT9uKGkpOmk7cmV0dXJuIGwucHJvdG9jb2w9PT1yLnByb3RvY29sJiZsLmhvc3Q9PT1yLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIHZBKEEpe2xldCB0PS9eKFstK1x3XXsxLDI1fSkoOj9cL1wvfDopLy5leGVjKEEpO3JldHVybiB0JiZ0WzFdfHwiIn1mdW5jdGlvbiBicihBLHQpe0E9QXx8MTA7bGV0IGU9bmV3IEFycmF5KEEpLHI9bmV3IEFycmF5KEEpLG49MCxhPTAsaTtyZXR1cm4gdD10IT09dm9pZCAwP3Q6MWUzLGZ1bmN0aW9uKHUpe2xldCBvPURhdGUubm93KCkscz1yW2FdO2l8fChpPW8pLGVbbl09dSxyW25dPW87bGV0IEM9YSxjPTA7Zm9yKDtDIT09bjspYys9ZVtDKytdLEM9QyVBO2lmKG49KG4rMSklQSxuPT09YSYmKGE9KGErMSklQSksby1pPHQpcmV0dXJuO2xldCBJPXMmJm8tcztyZXR1cm4gST9NYXRoLnJvdW5kKGMqMWUzL0kpOnZvaWQgMH19dmFyIExlPWJyO2Z1bmN0aW9uIFBlKEEsdCl7bGV0IGU9MCxyPUxlKDUwLDI1MCk7cmV0dXJuIG49PntsZXQgYT1uLmxvYWRlZCxpPW4ubGVuZ3RoQ29tcHV0YWJsZT9uLnRvdGFsOnZvaWQgMCxsPWEtZSx1PXIobCksbz1hPD1pO2U9YTtsZXQgcz17bG9hZGVkOmEsdG90YWw6aSxwcm9ncmVzczppP2EvaTp2b2lkIDAsYnl0ZXM6bCxyYXRlOnV8fHZvaWQgMCxlc3RpbWF0ZWQ6dSYmaSYmbz8oaS1hKS91OnZvaWQgMCxldmVudDpufTtzW3Q/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsQShzKX19dmFyIEZyPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsTWU9RnImJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihlLHIpe2xldCBuPUEuZGF0YSxhPUYuZnJvbShBLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGk9QS5yZXNwb25zZVR5cGUsbDtmdW5jdGlvbiB1KCl7QS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShsKSxBLnNpZ25hbCYmQS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGwpfWcuaXNGb3JtRGF0YShuKSYmKFMuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fFMuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/YS5zZXRDb250ZW50VHlwZSghMSk6YS5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YTsiLCExKSk7bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IEk9QS5hdXRoLnVzZXJuYW1lfHwiIixmPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7YS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoSSsiOiIrZikpfWxldCBzPWFBKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksdEEocyxBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIEMoKXtpZighbylyZXR1cm47bGV0IEk9Ri5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksQj17ZGF0YTohaXx8aT09PSJ0ZXh0Inx8aT09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOkksY29uZmlnOkEscmVxdWVzdDpvfTtIQShmdW5jdGlvbihtKXtlKG0pLHUoKX0sZnVuY3Rpb24obSl7cihtKSx1KCl9LEIpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9QzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoQyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihyKG5ldyBkKCJSZXF1ZXN0IGFib3J0ZWQiLGQuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe3IobmV3IGQoIk5ldHdvcmsgRXJyb3IiLGQuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBmPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixCPUEudHJhbnNpdGlvbmFsfHx1QTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihmPUEudGltZW91dEVycm9yTWVzc2FnZSkscihuZXcgZChmLEIuY2xhcmlmeVRpbWVvdXRFcnJvcj9kLkVUSU1FRE9VVDpkLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LFMuaXNTdGFuZGFyZEJyb3dzZXJFbnYpe2xldCBJPShBLndpdGhDcmVkZW50aWFsc3x8eGUocykpJiZBLnhzcmZDb29raWVOYW1lJiZHZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO0kmJmEuc2V0KEEueHNyZkhlYWRlck5hbWUsSSl9bj09PXZvaWQgMCYmYS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBvJiZnLmZvckVhY2goYS50b0pTT04oKSxmdW5jdGlvbihmLEIpe28uc2V0UmVxdWVzdEhlYWRlcihCLGYpfSksZy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChvLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxpJiZpIT09Impzb24iJiYoby5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsUGUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLnVwbG9hZCYmby51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFBlKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihsPUk9PntvJiYocighSXx8SS50eXBlP25ldyBQKG51bGwsQSxvKTpJKSxvLmFib3J0KCksbz1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobCksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP2woKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbCkpKTtsZXQgYz12QShzKTtpZihjJiZTLnByb3RvY29scy5pbmRleE9mKGMpPT09LTEpe3IobmV3IGQoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrYysiOiIsZC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1vLnNlbmQobnx8bnVsbCl9KX07dmFyIGRBPXtodHRwOmNBLHhocjpNZX07Zy5mb3JFYWNoKGRBLChBLHQpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6dH0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTp0fSl9fSk7dmFyIEplPXtnZXRBZGFwdGVyOkE9PntBPWcuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOnR9PUEsZSxyO2ZvcihsZXQgbj0wO248dCYmKGU9QVtuXSwhKHI9Zy5pc1N0cmluZyhlKT9kQVtlLnRvTG93ZXJDYXNlKCldOmUpKTtuKyspO2lmKCFyKXRocm93IHI9PT0hMT9uZXcgZChgQWRhcHRlciAke2V9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50YCwiRVJSX05PVF9TVVBQT1JUIik6bmV3IEVycm9yKGcuaGFzT3duUHJvcChkQSxlKT9gQWRhcHRlciAnJHtlfScgaXMgbm90IGF2YWlsYWJsZSBpbiB0aGUgYnVpbGRgOmBVbmtub3duIGFkYXB0ZXIgJyR7ZX0nYCk7aWYoIWcuaXNGdW5jdGlvbihyKSl0aHJvdyBuZXcgVHlwZUVycm9yKCJhZGFwdGVyIGlzIG5vdCBhIGZ1bmN0aW9uIik7cmV0dXJuIHJ9LGFkYXB0ZXJzOmRBfTtmdW5jdGlvbiBLQShBKXtpZihBLmNhbmNlbFRva2VuJiZBLmNhbmNlbFRva2VuLnRocm93SWZSZXF1ZXN0ZWQoKSxBLnNpZ25hbCYmQS5zaWduYWwuYWJvcnRlZCl0aHJvdyBuZXcgUChudWxsLEEpfWZ1bmN0aW9uIFFBKEEpe3JldHVybiBLQShBKSxBLmhlYWRlcnM9Ri5mcm9tKEEuaGVhZGVycyksQS5kYXRhPW5BLmNhbGwoQSxBLnRyYW5zZm9ybVJlcXVlc3QpLFsicG9zdCIsInB1dCIsInBhdGNoIl0uaW5kZXhPZihBLm1ldGhvZCkhPT0tMSYmQS5oZWFkZXJzLnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQiLCExKSxKZS5nZXRBZGFwdGVyKEEuYWRhcHRlcnx8ai5hZGFwdGVyKShBKS50aGVuKGZ1bmN0aW9uKHIpe3JldHVybiBLQShBKSxyLmRhdGE9bkEuY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2Usciksci5oZWFkZXJzPUYuZnJvbShyLmhlYWRlcnMpLHJ9LGZ1bmN0aW9uKHIpe3JldHVybiBpQShyKXx8KEtBKEEpLHImJnIucmVzcG9uc2UmJihyLnJlc3BvbnNlLmRhdGE9bkEuY2FsbChBLEEudHJhbnNmb3JtUmVzcG9uc2Usci5yZXNwb25zZSksci5yZXNwb25zZS5oZWFkZXJzPUYuZnJvbShyLnJlc3BvbnNlLmhlYWRlcnMpKSksUHJvbWlzZS5yZWplY3Qocil9KX12YXIgSGU9QT0+QSBpbnN0YW5jZW9mIEY/QS50b0pTT04oKTpBO2Z1bmN0aW9uIHgoQSx0KXt0PXR8fHt9O2xldCBlPXt9O2Z1bmN0aW9uIHIobyxzLEMpe3JldHVybiBnLmlzUGxhaW5PYmplY3QobykmJmcuaXNQbGFpbk9iamVjdChzKT9nLm1lcmdlLmNhbGwoe2Nhc2VsZXNzOkN9LG8scyk6Zy5pc1BsYWluT2JqZWN0KHMpP2cubWVyZ2Uoe30scyk6Zy5pc0FycmF5KHMpP3Muc2xpY2UoKTpzfWZ1bmN0aW9uIG4obyxzLEMpe2lmKGcuaXNVbmRlZmluZWQocykpe2lmKCFnLmlzVW5kZWZpbmVkKG8pKXJldHVybiByKHZvaWQgMCxvLEMpfWVsc2UgcmV0dXJuIHIobyxzLEMpfWZ1bmN0aW9uIGEobyxzKXtpZighZy5pc1VuZGVmaW5lZChzKSlyZXR1cm4gcih2b2lkIDAscyl9ZnVuY3Rpb24gaShvLHMpe2lmKGcuaXNVbmRlZmluZWQocykpe2lmKCFnLmlzVW5kZWZpbmVkKG8pKXJldHVybiByKHZvaWQgMCxvKX1lbHNlIHJldHVybiByKHZvaWQgMCxzKX1mdW5jdGlvbiBsKG8scyxDKXtpZihDIGluIHQpcmV0dXJuIHIobyxzKTtpZihDIGluIEEpcmV0dXJuIHIodm9pZCAwLG8pfWxldCB1PXt1cmw6YSxtZXRob2Q6YSxkYXRhOmEsYmFzZVVSTDppLHRyYW5zZm9ybVJlcXVlc3Q6aSx0cmFuc2Zvcm1SZXNwb25zZTppLHBhcmFtc1NlcmlhbGl6ZXI6aSx0aW1lb3V0OmksdGltZW91dE1lc3NhZ2U6aSx3aXRoQ3JlZGVudGlhbHM6aSxhZGFwdGVyOmkscmVzcG9uc2VUeXBlOmkseHNyZkNvb2tpZU5hbWU6aSx4c3JmSGVhZGVyTmFtZTppLG9uVXBsb2FkUHJvZ3Jlc3M6aSxvbkRvd25sb2FkUHJvZ3Jlc3M6aSxkZWNvbXByZXNzOmksbWF4Q29udGVudExlbmd0aDppLG1heEJvZHlMZW5ndGg6aSxiZWZvcmVSZWRpcmVjdDppLHRyYW5zcG9ydDppLGh0dHBBZ2VudDppLGh0dHBzQWdlbnQ6aSxjYW5jZWxUb2tlbjppLHNvY2tldFBhdGg6aSxyZXNwb25zZUVuY29kaW5nOmksdmFsaWRhdGVTdGF0dXM6bCxoZWFkZXJzOihvLHMpPT5uKEhlKG8pLEhlKHMpLCEwKX07cmV0dXJuIGcuZm9yRWFjaChPYmplY3Qua2V5cyhPYmplY3QuYXNzaWduKHt9LEEsdCkpLGZ1bmN0aW9uKHMpe2xldCBDPXVbc118fG4sYz1DKEFbc10sdFtzXSxzKTtnLmlzVW5kZWZpbmVkKGMpJiZDIT09bHx8KGVbc109Yyl9KSxlfXZhciBwQT0iMS40LjAiO3ZhciBXQT17fTtbIm9iamVjdCIsImJvb2xlYW4iLCJudW1iZXIiLCJmdW5jdGlvbiIsInN0cmluZyIsInN5bWJvbCJdLmZvckVhY2goKEEsdCk9PntXQVtBXT1mdW5jdGlvbihyKXtyZXR1cm4gdHlwZW9mIHI9PT1BfHwiYSIrKHQ8MT8ibiAiOiIgIikrQX19KTt2YXIgWWU9e307V0EudHJhbnNpdGlvbmFsPWZ1bmN0aW9uKHQsZSxyKXtmdW5jdGlvbiBuKGEsaSl7cmV0dXJuIltBeGlvcyB2IitwQSsiXSBUcmFuc2l0aW9uYWwgb3B0aW9uICciK2ErIiciK2krKHI/Ii4gIityOiIiKX1yZXR1cm4oYSxpLGwpPT57aWYodD09PSExKXRocm93IG5ldyBkKG4oaSwiIGhhcyBiZWVuIHJlbW92ZWQiKyhlPyIgaW4gIitlOiIiKSksZC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIGUmJiFZZVtpXSYmKFllW2ldPSEwLGNvbnNvbGUud2FybihuKGksIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK2UrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksdD90KGEsaSxsKTohMH19O2Z1bmN0aW9uIGtyKEEsdCxlKXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGQoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGQuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCByPU9iamVjdC5rZXlzKEEpLG49ci5sZW5ndGg7Zm9yKDtuLS0gPjA7KXtsZXQgYT1yW25dLGk9dFthXTtpZihpKXtsZXQgbD1BW2FdLHU9bD09PXZvaWQgMHx8aShsLGEsQSk7aWYodSE9PSEwKXRocm93IG5ldyBkKCJvcHRpb24gIithKyIgbXVzdCBiZSAiK3UsZC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYoZSE9PSEwKXRocm93IG5ldyBkKCJVbmtub3duIG9wdGlvbiAiK2EsZC5FUlJfQkFEX09QVElPTil9fXZhciBtQT17YXNzZXJ0T3B0aW9uczprcix2YWxpZGF0b3JzOldBfTt2YXIgTT1tQS52YWxpZGF0b3JzLHo9Y2xhc3N7Y29uc3RydWN0b3IodCl7dGhpcy5kZWZhdWx0cz10LHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBQQSxyZXNwb25zZTpuZXcgUEF9fXJlcXVlc3QodCxlKXt0eXBlb2YgdD09InN0cmluZyI/KGU9ZXx8e30sZS51cmw9dCk6ZT10fHx7fSxlPXgodGhpcy5kZWZhdWx0cyxlKTtsZXR7dHJhbnNpdGlvbmFsOnIscGFyYW1zU2VyaWFsaXplcjpuLGhlYWRlcnM6YX09ZTtyIT09dm9pZCAwJiZtQS5hc3NlcnRPcHRpb25zKHIse3NpbGVudEpTT05QYXJzaW5nOk0udHJhbnNpdGlvbmFsKE0uYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOk0udHJhbnNpdGlvbmFsKE0uYm9vbGVhbil9LCExKSxuIT1udWxsJiYoZy5pc0Z1bmN0aW9uKG4pP2UucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOm59Om1BLmFzc2VydE9wdGlvbnMobix7ZW5jb2RlOk0uZnVuY3Rpb24sc2VyaWFsaXplOk0uZnVuY3Rpb259LCEwKSksZS5tZXRob2Q9KGUubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGk7aT1hJiZnLm1lcmdlKGEuY29tbW9uLGFbZS5tZXRob2RdKSxpJiZnLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sZj0+e2RlbGV0ZSBhW2ZdfSksZS5oZWFkZXJzPUYuY29uY2F0KGksYSk7bGV0IGw9W10sdT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oQil7dHlwZW9mIEIucnVuV2hlbj09ImZ1bmN0aW9uIiYmQi5ydW5XaGVuKGUpPT09ITF8fCh1PXUmJkIuc3luY2hyb25vdXMsbC51bnNoaWZ0KEIuZnVsZmlsbGVkLEIucmVqZWN0ZWQpKX0pO2xldCBvPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oQil7by5wdXNoKEIuZnVsZmlsbGVkLEIucmVqZWN0ZWQpfSk7bGV0IHMsQz0wLGM7aWYoIXUpe2xldCBmPVtRQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKGYudW5zaGlmdC5hcHBseShmLGwpLGYucHVzaC5hcHBseShmLG8pLGM9Zi5sZW5ndGgscz1Qcm9taXNlLnJlc29sdmUoZSk7QzxjOylzPXMudGhlbihmW0MrK10sZltDKytdKTtyZXR1cm4gc31jPWwubGVuZ3RoO2xldCBJPWU7Zm9yKEM9MDtDPGM7KXtsZXQgZj1sW0MrK10sQj1sW0MrK107dHJ5e0k9ZihJKX1jYXRjaChwKXtCLmNhbGwodGhpcyxwKTticmVha319dHJ5e3M9UUEuY2FsbCh0aGlzLEkpfWNhdGNoKGYpe3JldHVybiBQcm9taXNlLnJlamVjdChmKX1mb3IoQz0wLGM9by5sZW5ndGg7QzxjOylzPXMudGhlbihvW0MrK10sb1tDKytdKTtyZXR1cm4gc31nZXRVcmkodCl7dD14KHRoaXMuZGVmYXVsdHMsdCk7bGV0IGU9YUEodC5iYXNlVVJMLHQudXJsKTtyZXR1cm4gdEEoZSx0LnBhcmFtcyx0LnBhcmFtc1NlcmlhbGl6ZXIpfX07Zy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbih0KXt6LnByb3RvdHlwZVt0XT1mdW5jdGlvbihlLHIpe3JldHVybiB0aGlzLnJlcXVlc3QoeChyfHx7fSx7bWV0aG9kOnQsdXJsOmUsZGF0YToocnx8e30pLmRhdGF9KSl9fSk7Zy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24odCl7ZnVuY3Rpb24gZShyKXtyZXR1cm4gZnVuY3Rpb24oYSxpLGwpe3JldHVybiB0aGlzLnJlcXVlc3QoeChsfHx7fSx7bWV0aG9kOnQsaGVhZGVyczpyP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDphLGRhdGE6aX0pKX19ei5wcm90b3R5cGVbdF09ZSgpLHoucHJvdG90eXBlW3QrIkZvcm0iXT1lKCEwKX0pO3ZhciBvQT16O3ZhciBqQT1jbGFzcyBBe2NvbnN0cnVjdG9yKHQpe2lmKHR5cGVvZiB0IT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgZTt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oYSl7ZT1hfSk7bGV0IHI9dGhpczt0aGlzLnByb21pc2UudGhlbihuPT57aWYoIXIuX2xpc3RlbmVycylyZXR1cm47bGV0IGE9ci5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2EtLSA+MDspci5fbGlzdGVuZXJzW2FdKG4pO3IuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49bj0+e2xldCBhLGk9bmV3IFByb21pc2UobD0+e3Iuc3Vic2NyaWJlKGwpLGE9bH0pLnRoZW4obik7cmV0dXJuIGkuY2FuY2VsPWZ1bmN0aW9uKCl7ci51bnN1YnNjcmliZShhKX0saX0sdChmdW5jdGlvbihhLGksbCl7ci5yZWFzb258fChyLnJlYXNvbj1uZXcgUChhLGksbCksZShyLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZSh0KXtpZih0aGlzLnJlYXNvbil7dCh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaCh0KTp0aGlzLl9saXN0ZW5lcnM9W3RdfXVuc3Vic2NyaWJlKHQpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCBlPXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKHQpO2UhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZShlLDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgdDtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24obil7dD1ufSksY2FuY2VsOnR9fX0scWU9akE7ZnVuY3Rpb24gX0EoQSl7cmV0dXJuIGZ1bmN0aW9uKGUpe3JldHVybiBBLmFwcGx5KG51bGwsZSl9fWZ1bmN0aW9uIHpBKEEpe3JldHVybiBnLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciBWQT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXMoVkEpLmZvckVhY2goKFtBLHRdKT0+e1ZBW3RdPUF9KTt2YXIgdmU9VkE7ZnVuY3Rpb24gS2UoQSl7bGV0IHQ9bmV3IG9BKEEpLGU9JChvQS5wcm90b3R5cGUucmVxdWVzdCx0KTtyZXR1cm4gZy5leHRlbmQoZSxvQS5wcm90b3R5cGUsdCx7YWxsT3duS2V5czohMH0pLGcuZXh0ZW5kKGUsdCxudWxsLHthbGxPd25LZXlzOiEwfSksZS5jcmVhdGU9ZnVuY3Rpb24obil7cmV0dXJuIEtlKHgoQSxuKSl9LGV9dmFyIHk9S2Uoaik7eS5BeGlvcz1vQTt5LkNhbmNlbGVkRXJyb3I9UDt5LkNhbmNlbFRva2VuPXFlO3kuaXNDYW5jZWw9aUE7eS5WRVJTSU9OPXBBO3kudG9Gb3JtRGF0YT1MO3kuQXhpb3NFcnJvcj1kO3kuQ2FuY2VsPXkuQ2FuY2VsZWRFcnJvcjt5LmFsbD1mdW5jdGlvbih0KXtyZXR1cm4gUHJvbWlzZS5hbGwodCl9O3kuc3ByZWFkPV9BO3kuaXNBeGlvc0Vycm9yPXpBO3kubWVyZ2VDb25maWc9eDt5LkF4aW9zSGVhZGVycz1GO3kuZm9ybVRvSlNPTj1BPT5DQShnLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO3kuSHR0cFN0YXR1c0NvZGU9dmU7eS5kZWZhdWx0PXk7dmFyIFk9eTt2YXJ7QXhpb3M6Z28sQXhpb3NFcnJvcjpsbyxDYW5jZWxlZEVycm9yOmNvLGlzQ2FuY2VsOmZvLENhbmNlbFRva2VuOnVvLFZFUlNJT046Q28sYWxsOkJvLENhbmNlbDpFbyxpc0F4aW9zRXJyb3I6UW8sc3ByZWFkOnBvLHRvRm9ybURhdGE6bW8sQXhpb3NIZWFkZXJzOmhvLEh0dHBTdGF0dXNDb2RlOnlvLGZvcm1Ub0pTT046d28sbWVyZ2VDb25maWc6RG99PVk7dmFyIGplPVN5bWJvbCgiQ29tbGluay5wcm94eSIpLFJyPVN5bWJvbCgiQ29tbGluay5lbmRwb2ludCIpLCRBPVN5bWJvbCgiQ29tbGluay5yZWxlYXNlUHJveHkiKSxaQT1TeW1ib2woIkNvbWxpbmsuZmluYWxpemVyIikseUE9U3ltYm9sKCJDb21saW5rLnRocm93biIpLF9lPUE9PnR5cGVvZiBBPT0ib2JqZWN0IiYmQSE9PW51bGx8fHR5cGVvZiBBPT0iZnVuY3Rpb24iLFVyPXtjYW5IYW5kbGU6QT0+X2UoQSkmJkFbamVdLHNlcmlhbGl6ZShBKXtsZXR7cG9ydDE6dCxwb3J0MjplfT1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIFZlKEEsdCksW2UsW2VdXX0sZGVzZXJpYWxpemUoQSl7cmV0dXJuIEEuc3RhcnQoKSxBZShBKX19LE5yPXtjYW5IYW5kbGU6QT0+X2UoQSkmJnlBIGluIEEsc2VyaWFsaXplKHt2YWx1ZTpBfSl7bGV0IHQ7cmV0dXJuIEEgaW5zdGFuY2VvZiBFcnJvcj90PXtpc0Vycm9yOiEwLHZhbHVlOnttZXNzYWdlOkEubWVzc2FnZSxuYW1lOkEubmFtZSxzdGFjazpBLnN0YWNrfX06dD17aXNFcnJvcjohMSx2YWx1ZTpBfSxbdCxbXV19LGRlc2VyaWFsaXplKEEpe3Rocm93IEEuaXNFcnJvcj9PYmplY3QuYXNzaWduKG5ldyBFcnJvcihBLnZhbHVlLm1lc3NhZ2UpLEEudmFsdWUpOkEudmFsdWV9fSx6ZT1uZXcgTWFwKFtbInByb3h5IixVcl0sWyJ0aHJvdyIsTnJdXSk7ZnVuY3Rpb24gT3IoQSx0KXtmb3IobGV0IGUgb2YgQSlpZih0PT09ZXx8ZT09PSIqInx8ZSBpbnN0YW5jZW9mIFJlZ0V4cCYmZS50ZXN0KHQpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIFZlKEEsdD1nbG9iYWxUaGlzLGU9WyIqIl0pe3QuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gcihuKXtpZighbnx8IW4uZGF0YSlyZXR1cm47aWYoIU9yKGUsbi5vcmlnaW4pKXtjb25zb2xlLndhcm4oYEludmFsaWQgb3JpZ2luICcke24ub3JpZ2lufScgZm9yIGNvbWxpbmsgcHJveHlgKTtyZXR1cm59bGV0e2lkOmEsdHlwZTppLHBhdGg6bH09T2JqZWN0LmFzc2lnbih7cGF0aDpbXX0sbi5kYXRhKSx1PShuLmRhdGEuYXJndW1lbnRMaXN0fHxbXSkubWFwKHEpLG87dHJ5e2xldCBzPWwuc2xpY2UoMCwtMSkucmVkdWNlKChjLEkpPT5jW0ldLEEpLEM9bC5yZWR1Y2UoKGMsSSk9PmNbSV0sQSk7c3dpdGNoKGkpe2Nhc2UiR0VUIjpvPUM7YnJlYWs7Y2FzZSJTRVQiOnNbbC5zbGljZSgtMSlbMF1dPXEobi5kYXRhLnZhbHVlKSxvPSEwO2JyZWFrO2Nhc2UiQVBQTFkiOm89Qy5hcHBseShzLHUpO2JyZWFrO2Nhc2UiQ09OU1RSVUNUIjp7bGV0IGM9bmV3IEMoLi4udSk7bz1QcihjKX1icmVhaztjYXNlIkVORFBPSU5UIjp7bGV0e3BvcnQxOmMscG9ydDI6SX09bmV3IE1lc3NhZ2VDaGFubmVsO1ZlKEEsSSksbz1lZShjLFtjXSl9YnJlYWs7Y2FzZSJSRUxFQVNFIjpvPXZvaWQgMDticmVhaztkZWZhdWx0OnJldHVybn19Y2F0Y2gocyl7bz17dmFsdWU6cyxbeUFdOjB9fVByb21pc2UucmVzb2x2ZShvKS5jYXRjaChzPT4oe3ZhbHVlOnMsW3lBXTowfSkpLnRoZW4ocz0+e2xldFtDLGNdPVNBKHMpO3QucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LEMpLHtpZDphfSksYyksaT09PSJSRUxFQVNFIiYmKHQucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsciksWmUodCksWkEgaW4gQSYmdHlwZW9mIEFbWkFdPT0iZnVuY3Rpb24iJiZBW1pBXSgpKX0pLmNhdGNoKHM9PntsZXRbQyxjXT1TQSh7dmFsdWU6bmV3IFR5cGVFcnJvcigiVW5zZXJpYWxpemFibGUgcmV0dXJuIHZhbHVlIiksW3lBXTowfSk7dC5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sQykse2lkOmF9KSxjKX0pfSksdC5zdGFydCYmdC5zdGFydCgpfWZ1bmN0aW9uIFRyKEEpe3JldHVybiBBLmNvbnN0cnVjdG9yLm5hbWU9PT0iTWVzc2FnZVBvcnQifWZ1bmN0aW9uIFplKEEpe1RyKEEpJiZBLmNsb3NlKCl9ZnVuY3Rpb24gQWUoQSx0KXtyZXR1cm4gWEEoQSxbXSx0KX1mdW5jdGlvbiBoQShBKXtpZihBKXRocm93IG5ldyBFcnJvcigiUHJveHkgaGFzIGJlZW4gcmVsZWFzZWQgYW5kIGlzIG5vdCB1c2VhYmxlIil9ZnVuY3Rpb24gWGUoQSl7cmV0dXJuIFYoQSx7dHlwZToiUkVMRUFTRSJ9KS50aGVuKCgpPT57WmUoQSl9KX12YXIgd0E9bmV3IFdlYWtNYXAsREE9IkZpbmFsaXphdGlvblJlZ2lzdHJ5ImluIGdsb2JhbFRoaXMmJm5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeShBPT57bGV0IHQ9KHdBLmdldChBKXx8MCktMTt3QS5zZXQoQSx0KSx0PT09MCYmWGUoQSl9KTtmdW5jdGlvbiBHcihBLHQpe2xldCBlPSh3QS5nZXQodCl8fDApKzE7d0Euc2V0KHQsZSksREEmJkRBLnJlZ2lzdGVyKEEsdCxBKX1mdW5jdGlvbiB4cihBKXtEQSYmREEudW5yZWdpc3RlcihBKX1mdW5jdGlvbiBYQShBLHQ9W10sZT1mdW5jdGlvbigpe30pe2xldCByPSExLG49bmV3IFByb3h5KGUse2dldChhLGkpe2lmKGhBKHIpLGk9PT0kQSlyZXR1cm4oKT0+e3hyKG4pLFhlKEEpLHI9ITB9O2lmKGk9PT0idGhlbiIpe2lmKHQubGVuZ3RoPT09MClyZXR1cm57dGhlbjooKT0+bn07bGV0IGw9VihBLHt0eXBlOiJHRVQiLHBhdGg6dC5tYXAodT0+dS50b1N0cmluZygpKX0pLnRoZW4ocSk7cmV0dXJuIGwudGhlbi5iaW5kKGwpfXJldHVybiBYQShBLFsuLi50LGldKX0sc2V0KGEsaSxsKXtoQShyKTtsZXRbdSxvXT1TQShsKTtyZXR1cm4gVihBLHt0eXBlOiJTRVQiLHBhdGg6Wy4uLnQsaV0ubWFwKHM9PnMudG9TdHJpbmcoKSksdmFsdWU6dX0sbykudGhlbihxKX0sYXBwbHkoYSxpLGwpe2hBKHIpO2xldCB1PXRbdC5sZW5ndGgtMV07aWYodT09PVJyKXJldHVybiBWKEEse3R5cGU6IkVORFBPSU5UIn0pLnRoZW4ocSk7aWYodT09PSJiaW5kIilyZXR1cm4gWEEoQSx0LnNsaWNlKDAsLTEpKTtsZXRbbyxzXT1XZShsKTtyZXR1cm4gVihBLHt0eXBlOiJBUFBMWSIscGF0aDp0Lm1hcChDPT5DLnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpvfSxzKS50aGVuKHEpfSxjb25zdHJ1Y3QoYSxpKXtoQShyKTtsZXRbbCx1XT1XZShpKTtyZXR1cm4gVihBLHt0eXBlOiJDT05TVFJVQ1QiLHBhdGg6dC5tYXAobz0+by50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6bH0sdSkudGhlbihxKX19KTtyZXR1cm4gR3IobixBKSxufWZ1bmN0aW9uIExyKEEpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLEEpfWZ1bmN0aW9uIFdlKEEpe2xldCB0PUEubWFwKFNBKTtyZXR1cm5bdC5tYXAoZT0+ZVswXSksTHIodC5tYXAoZT0+ZVsxXSkpXX12YXIgJGU9bmV3IFdlYWtNYXA7ZnVuY3Rpb24gZWUoQSx0KXtyZXR1cm4gJGUuc2V0KEEsdCksQX1mdW5jdGlvbiBQcihBKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihBLHtbamVdOiEwfSl9ZnVuY3Rpb24gU0EoQSl7Zm9yKGxldFt0LGVdb2YgemUpaWYoZS5jYW5IYW5kbGUoQSkpe2xldFtyLG5dPWUuc2VyaWFsaXplKEEpO3JldHVyblt7dHlwZToiSEFORExFUiIsbmFtZTp0LHZhbHVlOnJ9LG5dfXJldHVyblt7dHlwZToiUkFXIix2YWx1ZTpBfSwkZS5nZXQoQSl8fFtdXX1mdW5jdGlvbiBxKEEpe3N3aXRjaChBLnR5cGUpe2Nhc2UiSEFORExFUiI6cmV0dXJuIHplLmdldChBLm5hbWUpLmRlc2VyaWFsaXplKEEudmFsdWUpO2Nhc2UiUkFXIjpyZXR1cm4gQS52YWx1ZX19ZnVuY3Rpb24gVihBLHQsZSl7cmV0dXJuIG5ldyBQcm9taXNlKHI9PntsZXQgbj1NcigpO0EuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gYShpKXshaS5kYXRhfHwhaS5kYXRhLmlkfHxpLmRhdGEuaWQhPT1ufHwoQS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixhKSxyKGkuZGF0YSkpfSksQS5zdGFydCYmQS5zdGFydCgpLEEucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbih7aWQ6bn0sdCksZSl9KX1mdW5jdGlvbiBNcigpe3JldHVybiBuZXcgQXJyYXkoNCkuZmlsbCgwKS5tYXAoKCk9Pk1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikudG9TdHJpbmcoMTYpKS5qb2luKCItIil9ZnVuY3Rpb24gZXQoQSl7bGV0IHQ9QWUoQSksZT1BO3JldHVybiBlLndvcmtlclByb3h5PXQsZS5vcmlnaW5hbFRlcm1pbmF0ZT1lLnRlcm1pbmF0ZSxlLnRlcm1pbmF0ZT0oKT0+e2Uud29ya2VyUHJveHlbJEFdKCksZS5vcmlnaW5hbFRlcm1pbmF0ZSgpfSx7d29ya2VyUHJveHk6dCx3b3JrZXI6ZX19YXN5bmMgZnVuY3Rpb24gSnIoQSx0KXtsZXQgZTtpZihBIT1udWxsKXtsZXQgaT1BO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyhlPWkud29ya2VyUHJveHkse3dvcmtlclByb3h5OmUsd29ya2VyOml9KTpldChBKX1sZXQgcj10eXBlb2YgdD4idSI/di5waXBlbGluZVdvcmtlclVybDp0LG49bnVsbCxhPXYud2ViV29ya2Vyc1VybDtpZih0eXBlb2YgYTwidSIpe2NvbnNvbGUud2FybigiaXRrQ29uZmlnIHdlYldvcmtlcnNVcmwgaXMgZGVwcmVjYXRlZC4gUGxlYXNlIHVzZSBwaXBlbGluZVdvcmtlclVybCB3aXRoIHRoZSBmdWxsIHBhdGggdG8gdGhlIHBpcGVsaW5lIHdvcmtlci4iKTtsZXQgaT0ibWluLiIsbD1hO2lmKGwuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgdT1hd2FpdCBZLmdldChgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHtyZXNwb25zZVR5cGU6ImJsb2IifSksbz1VUkwuY3JlYXRlT2JqZWN0VVJMKHUuZGF0YSk7bj1uZXcgV29ya2VyKG8se3R5cGU6Im1vZHVsZSJ9KX1lbHNlIG49bmV3IFdvcmtlcihgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBpZihyPT09bnVsbCluPW5ldyBXb3JrZXIobmV3IFVSTCgiLi93ZWItd29ya2Vycy9pdGstd2FzbS1waXBlbGluZS53b3JrZXIuanMiLGltcG9ydC5tZXRhLnVybCkse3R5cGU6Im1vZHVsZSJ9KTtlbHNlIGlmKHIuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgaT1hd2FpdCBZLmdldChyLHtyZXNwb25zZVR5cGU6ImJsb2IifSksbD1VUkwuY3JlYXRlT2JqZWN0VVJMKGkuZGF0YSk7bj1uZXcgV29ya2VyKGwse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIG49bmV3IFdvcmtlcihyLHt0eXBlOiJtb2R1bGUifSk7cmV0dXJuIGV0KG4pfXZhciB0dD1Kcjt2YXIgSHI7ZnVuY3Rpb24gcnQoKXtyZXR1cm4gSHJ9dmFyIFlyO2Z1bmN0aW9uIG50KCl7cmV0dXJuIFlyfWZ1bmN0aW9uIHFyKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciB0ZT1xcjtmdW5jdGlvbiB2cihBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgaXQ9dnI7YXN5bmMgZnVuY3Rpb24gS3IoQSx0KXtsZXQgZT0idW5rbm93biI7dHlwZW9mIEEhPSJzdHJpbmciP2U9QS5ocmVmOkEuc3RhcnRzV2l0aCgiaHR0cCIpP2U9QTplPWAke3R9LyR7QX1gLGUuZW5kc1dpdGgoIi5qcyIpJiYoZT1lLnN1YnN0cmluZygwLGUubGVuZ3RoLTMpKSxlLmVuZHNXaXRoKCIud2FzbSIpJiYoZT1lLnN1YnN0cmluZygwLGUubGVuZ3RoLTUpKTtsZXQgcj1gJHtlfS53YXNtYCxhPShhd2FpdCBZLmdldChyLHtyZXNwb25zZVR5cGU6ImFycmF5YnVmZmVyIn0pKS5kYXRhO3JldHVybihhd2FpdCBpbXBvcnQoYCR7ZX0uanNgKSkuZGVmYXVsdCh7d2FzbUJpbmFyeTphfSl9dmFyIGF0PUtyO3ZhciBvdD1hc3luYygpPT5XZWJBc3NlbWJseS52YWxpZGF0ZShuZXcgVWludDhBcnJheShbMCw5NywxMTUsMTA5LDEsMCwwLDAsMSw1LDEsOTYsMCwxLDEyMywzLDIsMSwwLDEwLDEwLDEsOCwwLDY1LDAsMjUzLDE1LDI1Myw5OCwxMV0pKTt2YXIgZ3Q9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI9PSJmdW5jdGlvbiIsc3Q9bmV3IFRleHRFbmNvZGVyLEl0PW5ldyBUZXh0RGVjb2RlcigidXRmLTgiKTtmdW5jdGlvbiBKKEEsdCl7bGV0IGU9e2ZsYWdzOiJyIixlbmNvZGluZzoiYmluYXJ5In0scj1BLmZzX29wZW4odCxlLmZsYWdzKSxhPUEuZnNfc3RhdCh0KS5zaXplLGk9bnVsbDtndD9pPW5ldyBTaGFyZWRBcnJheUJ1ZmZlcihhKTppPW5ldyBBcnJheUJ1ZmZlcihhKTtsZXQgbD1uZXcgVWludDhBcnJheShpKTtyZXR1cm4gQS5mc19yZWFkKHIsbCwwLGEsMCksQS5mc19jbG9zZShyKSxsfWZ1bmN0aW9uIGx0KEEsdCxlKXtsZXQgcj1udWxsO2d0P3I9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGUpOnI9bmV3IEFycmF5QnVmZmVyKGUpO2xldCBuPW5ldyBVaW50OEFycmF5KHIpLGE9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLHQsZSk7cmV0dXJuIG4uc2V0KGEpLG59ZnVuY3Rpb24gYihBLHQsZSxyKXtsZXQgbj0wO3JldHVybiB0IT09bnVsbCYmKG49QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfYXJyYXlfYWxsb2MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSxyLHQuYnVmZmVyLmJ5dGVMZW5ndGhdKSxBLkhFQVBVOC5zZXQobmV3IFVpbnQ4QXJyYXkodC5idWZmZXIpLG4pKSxufWZ1bmN0aW9uIFooQSx0LGUpe2xldCByPUpTT04uc3RyaW5naWZ5KHQpLG49QS5jY2FsbCgiaXRrX3dhc21faW5wdXRfanNvbl9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHIubGVuZ3RoXSk7QS53cml0ZUFzY2lpVG9NZW1vcnkocixuLCExKX1mdW5jdGlvbiBSKEEsdCxlLHIpe2xldCBuPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsZV0pLGE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsdCxlXSksaT1sdChBLG4sYSk7cmV0dXJuIHcocixpLmJ1ZmZlcil9ZnVuY3Rpb24gcmUoQSx0KXtsZXQgZT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfanNvbl9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciJdLFswLHRdKSxyPUEuQXNjaWlUb1N0cmluZyhlKTtyZXR1cm4gSlNPTi5wYXJzZShyKX1mdW5jdGlvbiBXcihBLHQsZSxyKXtyIT1udWxsJiZyLmxlbmd0aD4wJiZyLmZvckVhY2goZnVuY3Rpb24obyxzKXt2YXIgQztzd2l0Y2goby50eXBlKXtjYXNlIEUuVGV4dFN0cmVhbTp7bGV0IGM9c3QuZW5jb2RlKG8uZGF0YS5kYXRhKSxJPWIoQSxjLHMsMCksZj17c2l6ZTpjLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtJfWB9O1ooQSxmLHMpO2JyZWFrfWNhc2UgRS5Kc29uQ29tcGF0aWJsZTp7bGV0IGM9c3QuZW5jb2RlKEpTT04uc3RyaW5naWZ5KG8uZGF0YSkpLEk9YihBLGMscywwKSxmPXtzaXplOmMuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0l9YH07WihBLGYscyk7YnJlYWt9Y2FzZSBFLkJpbmFyeVN0cmVhbTp7bGV0IGM9by5kYXRhLmRhdGEsST1iKEEsYyxzLDApLGY9e3NpemU6Yy5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gfTtaKEEsZixzKTticmVha31jYXNlIEUuVGV4dEZpbGU6e0EuZnNfd3JpdGVGaWxlKG8uZGF0YS5wYXRoLG8uZGF0YS5kYXRhKTticmVha31jYXNlIEUuQmluYXJ5RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgRS5JbWFnZTp7bGV0IGM9by5kYXRhLEk9YihBLGMuZGF0YSxzLDApLGY9YihBLGMuZGlyZWN0aW9uLHMsMSksQj10eXBlb2YoKEM9Yy5tZXRhZGF0YSk9PT1udWxsfHxDPT09dm9pZCAwP3ZvaWQgMDpDLmVudHJpZXMpPCJ1Ij9KU09OLnN0cmluZ2lmeShBcnJheS5mcm9tKGMubWV0YWRhdGEuZW50cmllcygpKSk6IltdIixwPXtpbWFnZVR5cGU6Yy5pbWFnZVR5cGUsbmFtZTpjLm5hbWUsb3JpZ2luOmMub3JpZ2luLHNwYWNpbmc6Yy5zcGFjaW5nLGRpcmVjdGlvbjpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxzaXplOmMuc2l6ZSxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLG1ldGFkYXRhOkJ9O1ooQSxwLHMpO2JyZWFrfWNhc2UgRS5NZXNoOntsZXQgYz1vLmRhdGEsST1iKEEsYy5wb2ludHMscywwKSxmPWIoQSxjLmNlbGxzLHMsMSksQj1iKEEsYy5wb2ludERhdGEscywyKSxwPWIoQSxjLmNlbGxEYXRhLHMsMyksbT17bWVzaFR5cGU6Yy5tZXNoVHlwZSxuYW1lOmMubmFtZSxudW1iZXJPZlBvaW50czpjLm51bWJlck9mUG9pbnRzLHBvaW50czpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0l9YCxudW1iZXJPZkNlbGxzOmMubnVtYmVyT2ZDZWxscyxjZWxsczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxjZWxsQnVmZmVyU2l6ZTpjLmNlbGxCdWZmZXJTaXplLG51bWJlck9mUG9pbnRQaXhlbHM6Yy5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0J9YCxudW1iZXJPZkNlbGxQaXhlbHM6Yy5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtwfWB9O1ooQSxtLHMpO2JyZWFrfWNhc2UgRS5Qb2x5RGF0YTp7bGV0IGM9by5kYXRhLEk9YihBLGMucG9pbnRzLHMsMCksZj1iKEEsYy52ZXJ0aWNlcyxzLDEpLEI9YihBLGMubGluZXMscywyKSxwPWIoQSxjLnBvbHlnb25zLHMsMyksbT1iKEEsYy50cmlhbmdsZVN0cmlwcyxzLDQpLFE9YihBLGMucG9pbnREYXRhLHMsNSksaD1iKEEsYy5wb2ludERhdGEscyw2KSxiQT17cG9seURhdGFUeXBlOmMucG9seURhdGFUeXBlLG5hbWU6Yy5uYW1lLG51bWJlck9mUG9pbnRzOmMubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLHZlcnRpY2VzQnVmZmVyU2l6ZTpjLnZlcnRpY2VzQnVmZmVyU2l6ZSx2ZXJ0aWNlczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxsaW5lc0J1ZmZlclNpemU6Yy5saW5lc0J1ZmZlclNpemUsbGluZXM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtCfWAscG9seWdvbnNCdWZmZXJTaXplOmMucG9seWdvbnNCdWZmZXJTaXplLHBvbHlnb25zOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7cH1gLHRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZTpjLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZSx0cmlhbmdsZVN0cmlwczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YCxudW1iZXJPZlBvaW50UGl4ZWxzOmMubnVtYmVyT2ZQb2ludFBpeGVscyxwb2ludERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtRfWAsbnVtYmVyT2ZDZWxsUGl4ZWxzOmMubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7aH1gfTtaKEEsYkEscyk7YnJlYWt9Y2FzZSBrLlRleHQ6e0EuZnNfd3JpdGVGaWxlKG8ucGF0aCxvLmRhdGEpO2JyZWFrfWNhc2Ugay5CaW5hcnk6e0EuZnNfd3JpdGVGaWxlKG8ucGF0aCxvLmRhdGEpO2JyZWFrfWNhc2Ugay5JbWFnZTp7bGV0IGM9by5kYXRhLEk9e2ltYWdlVHlwZTpjLmltYWdlVHlwZSxuYW1lOmMubmFtZSxvcmlnaW46Yy5vcmlnaW4sc3BhY2luZzpjLnNwYWNpbmcsZGlyZWN0aW9uOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2RpcmVjdGlvbi5yYXciLHNpemU6Yy5zaXplLGRhdGE6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGF0YS5yYXcifTtpZihBLmZzX21rZGlycyhgJHtvLnBhdGh9L2RhdGFgKSxBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLEpTT04uc3RyaW5naWZ5KEkpKSxjLmRhdGE9PT1udWxsKXRocm93IEVycm9yKCJpbWFnZS5kYXRhIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGMuZGF0YS5idWZmZXIpKSxBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvZGlyZWN0aW9uLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYy5kaXJlY3Rpb24uYnVmZmVyKSk7YnJlYWt9Y2FzZSBrLk1lc2g6e2xldCBjPW8uZGF0YSxJPXttZXNoVHlwZTpjLm1lc2hUeXBlLG5hbWU6Yy5uYW1lLG51bWJlck9mUG9pbnRzOmMubnVtYmVyT2ZQb2ludHMscG9pbnRzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50cy5yYXciLG51bWJlck9mUG9pbnRQaXhlbHM6Yy5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9wb2ludERhdGEucmF3IixudW1iZXJPZkNlbGxzOmMubnVtYmVyT2ZDZWxscyxjZWxsczoiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9jZWxscy5yYXciLG51bWJlck9mQ2VsbFBpeGVsczpjLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9jZWxsRGF0YS5yYXciLGNlbGxCdWZmZXJTaXplOmMuY2VsbEJ1ZmZlclNpemV9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoSSkpLEkubnVtYmVyT2ZQb2ludHM+MCl7aWYoYy5wb2ludHM9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLnBvaW50cyBpcyBudWxsIik7QS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgLG5ldyBVaW50OEFycmF5KGMucG9pbnRzLmJ1ZmZlcikpfWlmKEkubnVtYmVyT2ZQb2ludFBpeGVscz4wKXtpZihjLnBvaW50RGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnREYXRhIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnREYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYy5wb2ludERhdGEuYnVmZmVyKSl9aWYoSS5udW1iZXJPZkNlbGxzPjApe2lmKGMuY2VsbHM9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLmNlbGxzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvY2VsbHMucmF3YCxuZXcgVWludDhBcnJheShjLmNlbGxzLmJ1ZmZlcikpfWlmKEkubnVtYmVyT2ZDZWxsUGl4ZWxzPjApe2lmKGMuY2VsbERhdGE9PT1udWxsKXRocm93IEVycm9yKCJtZXNoLmNlbGxEYXRhIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvY2VsbERhdGEucmF3YCxuZXcgVWludDhBcnJheShjLmNlbGxEYXRhLmJ1ZmZlcikpfWJyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIGlucHV0IEludGVyZmFjZVR5cGUiKX19KSxBLnJlc2V0TW9kdWxlU3Rkb3V0KCksQS5yZXNldE1vZHVsZVN0ZGVycigpO2xldCBuPUEuc3RhY2tTYXZlKCksYT0wO3RyeXthPUEuY2FsbE1haW4odC5zbGljZSgpKX1jYXRjaChvKXt0aHJvdyB0eXBlb2Ygbz09Im51bWJlciImJihjb25zb2xlLmxvZygiRXhjZXB0aW9uIHdoaWxlIHJ1bm5pbmcgcGlwZWxpbmU6IiksY29uc29sZS5sb2coInN0ZG91dDoiLEEuZ2V0TW9kdWxlU3Rkb3V0KCkpLGNvbnNvbGUuZXJyb3IoInN0ZGVycjoiLEEuZ2V0TW9kdWxlU3RkZXJyKCkpLHR5cGVvZiBBLmdldEV4Y2VwdGlvbk1lc3NhZ2U8InUiP2NvbnNvbGUuZXJyb3IoImV4Y2VwdGlvbjoiLEEuZ2V0RXhjZXB0aW9uTWVzc2FnZShvKSk6Y29uc29sZS5lcnJvcigiQnVpbGQgbW9kdWxlIGluIERlYnVnIG1vZGUgZm9yIGV4Y2VwdGlvbiBtZXNzYWdlIGluZm9ybWF0aW9uLiIpKSxvfWZpbmFsbHl7QS5zdGFja1Jlc3RvcmUobil9bGV0IGk9QS5nZXRNb2R1bGVTdGRvdXQoKSxsPUEuZ2V0TW9kdWxlU3RkZXJyKCksdT1bXTtyZXR1cm4gZSE9bnVsbCYmZS5sZW5ndGg+MCYmYT09PTAmJmUuZm9yRWFjaChmdW5jdGlvbihvLHMpe2xldCBDPW51bGw7c3dpdGNoKG8udHlwZSl7Y2FzZSBFLlRleHRTdHJlYW06e2xldCBJPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHMsMF0pLGY9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAscywwXSksQj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsSSxmKTtDPXtkYXRhOkl0LmRlY29kZShCKX07YnJlYWt9Y2FzZSBFLkpzb25Db21wYXRpYmxlOntsZXQgST1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxzLDBdKSxmPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHMsMF0pLEI9bmV3IFVpbnQ4QXJyYXkoQS5IRUFQVTguYnVmZmVyLEksZik7Qz1KU09OLnBhcnNlKEl0LmRlY29kZShCKSk7YnJlYWt9Y2FzZSBFLkJpbmFyeVN0cmVhbTp7bGV0IEk9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAscywwXSksZj1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxzLDBdKTtDPXtkYXRhOmx0KEEsSSxmKX07YnJlYWt9Y2FzZSBFLlRleHRGaWxlOntDPXtwYXRoOm8uZGF0YS5wYXRoLGRhdGE6QS5mc19yZWFkRmlsZShvLmRhdGEucGF0aCx7ZW5jb2Rpbmc6InV0ZjgifSl9O2JyZWFrfWNhc2UgRS5CaW5hcnlGaWxlOntDPXtwYXRoOm8uZGF0YS5wYXRoLGRhdGE6SihBLG8uZGF0YS5wYXRoKX07YnJlYWt9Y2FzZSBFLkltYWdlOntsZXQgST1yZShBLHMpO0kuZGF0YT1SKEEscywwLEkuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpLEkuZGlyZWN0aW9uPVIoQSxzLDEsSC5GbG9hdDY0KSxJLm1ldGFkYXRhPW5ldyBNYXAoSS5tZXRhZGF0YSksQz1JO2JyZWFrfWNhc2UgRS5NZXNoOntsZXQgST1yZShBLHMpO0kubnVtYmVyT2ZQb2ludHM+MD9JLnBvaW50cz1SKEEscywwLEkubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlKTpJLnBvaW50cz13KEkubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksSS5udW1iZXJPZkNlbGxzPjA/SS5jZWxscz1SKEEscywxLEkubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUpOkkuY2VsbHM9dyhJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksSS5udW1iZXJPZlBvaW50UGl4ZWxzPjA/SS5wb2ludERhdGE9UihBLHMsMixJLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpJLnBvaW50RGF0YT13KEkubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxJLm51bWJlck9mQ2VsbFBpeGVscz4wP0kuY2VsbERhdGE9UihBLHMsMyxJLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkkuY2VsbERhdGE9dyhJLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDPUk7YnJlYWt9Y2FzZSBFLlBvbHlEYXRhOntsZXQgST1yZShBLHMpO0kubnVtYmVyT2ZQb2ludHM+MD9JLnBvaW50cz1SKEEscywwLEguRmxvYXQzMik6SS5wb2ludHM9bmV3IEZsb2F0MzJBcnJheSxJLnZlcnRpY2VzQnVmZmVyU2l6ZT4wP0kudmVydGljZXM9UihBLHMsMSxELlVJbnQzMik6SS52ZXJ0aWNlcz1uZXcgVWludDMyQXJyYXksSS5saW5lc0J1ZmZlclNpemU+MD9JLmxpbmVzPVIoQSxzLDIsRC5VSW50MzIpOkkubGluZXM9bmV3IFVpbnQzMkFycmF5LEkucG9seWdvbnNCdWZmZXJTaXplPjA/SS5wb2x5Z29ucz1SKEEscywzLEQuVUludDMyKTpJLnBvbHlnb25zPW5ldyBVaW50MzJBcnJheSxJLnRyaWFuZ2xlU3RyaXBzQnVmZmVyU2l6ZT4wP0kudHJpYW5nbGVTdHJpcHM9UihBLHMsNCxELlVJbnQzMik6SS50cmlhbmdsZVN0cmlwcz1uZXcgVWludDMyQXJyYXksSS5udW1iZXJPZlBvaW50UGl4ZWxzPjA/SS5wb2ludERhdGE9UihBLHMsNSxJLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSk6SS5wb2ludERhdGE9dyhJLnBvbHlEYXRhVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEkubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/SS5jZWxsRGF0YT1SKEEscyw2LEkucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUpOkkuY2VsbERhdGE9dyhJLnBvbHlEYXRhVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQz1JO2JyZWFrfWNhc2Ugay5UZXh0OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Qz1BLmZzX3JlYWRGaWxlKG8ucGF0aCx7ZW5jb2Rpbmc6InV0ZjgifSk7YnJlYWt9Y2FzZSBrLkJpbmFyeTp7aWYodHlwZW9mIG8ucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO0M9SihBLG8ucGF0aCk7YnJlYWt9Y2FzZSBrLkltYWdlOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEk9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxmPUpTT04ucGFyc2UoSSksQj1KKEEsYCR7by5wYXRofS9kYXRhL2RhdGEucmF3YCk7Zi5kYXRhPXcoZi5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSxCLmJ1ZmZlcik7bGV0IHA9SihBLGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCk7Zi5kaXJlY3Rpb249dyhILkZsb2F0NjQscC5idWZmZXIpLEM9ZjticmVha31jYXNlIGsuTWVzaDp7aWYodHlwZW9mIG8ucGF0aD4idSIpdGhyb3cgbmV3IEVycm9yKCJvdXRwdXQucGF0aCBub3QgZGVmaW5lZCIpO2xldCBJPUEuZnNfcmVhZEZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCx7ZW5jb2Rpbmc6InV0ZjgifSksZj1KU09OLnBhcnNlKEkpO2lmKGYubnVtYmVyT2ZQb2ludHM+MCl7bGV0IEI9SihBLGAke28ucGF0aH0vZGF0YS9wb2ludHMucmF3YCk7Zi5wb2ludHM9dyhmLm1lc2hUeXBlLnBvaW50Q29tcG9uZW50VHlwZSxCLmJ1ZmZlcil9ZWxzZSBmLnBvaW50cz13KGYubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoZi5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2xldCBCPUooQSxgJHtvLnBhdGh9L2RhdGEvcG9pbnREYXRhLnJhd2ApO2YucG9pbnREYXRhPXcoZi5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxCLmJ1ZmZlcil9ZWxzZSBmLnBvaW50RGF0YT13KGYubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihmLm51bWJlck9mQ2VsbHM+MCl7bGV0IEI9SihBLGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgKTtmLmNlbGxzPXcoZi5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxCLmJ1ZmZlcil9ZWxzZSBmLmNlbGxzPXcoZi5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKGYubnVtYmVyT2ZDZWxsUGl4ZWxzPjApe2xldCBCPUooQSxgJHtvLnBhdGh9L2RhdGEvY2VsbERhdGEucmF3YCk7Zi5jZWxsRGF0YT13KGYubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxCLmJ1ZmZlcil9ZWxzZSBmLmNlbGxEYXRhPXcoZi5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7Qz1mO2JyZWFrfWRlZmF1bHQ6dGhyb3cgRXJyb3IoIlVuc3VwcG9ydGVkIG91dHB1dCBJbnRlcmZhY2VUeXBlIil9bGV0IGM9e3R5cGU6by50eXBlLGRhdGE6Q307dS5wdXNoKGMpfSkse3JldHVyblZhbHVlOmEsc3Rkb3V0Omksc3RkZXJyOmwsb3V0cHV0czp1fX12YXIgY3Q9V3I7dmFyIG5lPW5ldyBNYXA7YXN5bmMgZnVuY3Rpb24ganIoQSl7bGV0IHQ9QSxlPUE7aWYodHlwZW9mIEEhPSJzdHJpbmciJiYodD1uZXcgVVJMKEEuaHJlZiksZT10LmhyZWYpLG5lLmhhcyhlKSlyZXR1cm4gbmUuZ2V0KGUpO3tsZXQgcj1hd2FpdCBhdChBLHYucGlwZWxpbmVzVXJsKTtyZXR1cm4gbmUuc2V0KGUscikscn19YXN5bmMgZnVuY3Rpb24gX3IoQSx0LGUscixuLGEpe3ZhciBpLGw7aWYoIWF3YWl0IG90KCkpe2xldCBRPSJXZWJBc3NlbWJseSBTSU1EIHN1cHBvcnQgaXMgcmVxdWlyZWQgLS0gcGxlYXNlIHVwZGF0ZSB5b3VyIGJyb3dzZXIuIjt0aHJvdyBhbGVydChRKSxuZXcgRXJyb3IoUSl9aWYoQT09PSExKXtsZXQgUT1hd2FpdCBqcih0LnRvU3RyaW5nKCkpO3JldHVybiBjdChRLGUscixuKX1sZXQgdT1BLG89KGk9YT8ucGlwZWxpbmVXb3JrZXJVcmwpIT09bnVsbCYmaSE9PXZvaWQgMD9pOm51bGwscz10eXBlb2YgbyE9InN0cmluZyImJnR5cGVvZiBvPy5ocmVmPCJ1Ij9vLmhyZWY6byx7d29ya2VyUHJveHk6Qyx3b3JrZXI6Y309YXdhaXQgdHQodSxzKTt1PWM7bGV0IEk9W107biE9bnVsbCYmbi5sZW5ndGg+MCYmbi5mb3JFYWNoKGZ1bmN0aW9uKFEpe2lmKFEudHlwZT09PUUuQmluYXJ5U3RyZWFtKXtsZXQgaD1RLmRhdGEuZGF0YTtJLnB1c2goaCl9ZWxzZSBpZihRLnR5cGU9PT1FLkJpbmFyeUZpbGUpe2xldCBoPVEuZGF0YS5kYXRhO0kucHVzaChoKX1lbHNlIGlmKFEudHlwZT09PUUuSW1hZ2Upe2xldCBoPVEuZGF0YTtpZihoLmRhdGE9PT1udWxsKXRocm93IEVycm9yKCJpbWFnZSBkYXRhIGNhbm5vdCBiZSBudWxsIik7SS5wdXNoKC4uLnRlKGgpKX1lbHNlIGlmKFEudHlwZT09PWsuQmluYXJ5KUkucHVzaChRLmRhdGEpO2Vsc2UgaWYoUS50eXBlPT09ay5JbWFnZSl7bGV0IGg9US5kYXRhO2lmKGguZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlIGRhdGEgY2Fubm90IGJlIG51bGwiKTtJLnB1c2goLi4udGUoaCkpfWVsc2UgaWYoUS50eXBlPT09ay5NZXNoKXtsZXQgaD1RLmRhdGE7SS5wdXNoKC4uLml0KGgpKX19KTtsZXQgZj0obD1hPy5waXBlbGluZUJhc2VVcmwpIT09bnVsbCYmbCE9PXZvaWQgMD9sOiJwaXBlbGluZXNVcmwiLEI9dHlwZW9mIGYhPSJzdHJpbmciJiZ0eXBlb2YgZj8uaHJlZjwidSI/Zi5ocmVmOmYscD1uIT1udWxsP2VlKG4sY2UoSSkpOm51bGwsbT1hd2FpdCBDLnJ1blBpcGVsaW5lKHYsdC50b1N0cmluZygpLEIsZSxyLHApO3JldHVybntyZXR1cm5WYWx1ZTptLnJldHVyblZhbHVlLHN0ZG91dDptLnN0ZG91dCxzdGRlcnI6bS5zdGRlcnIsb3V0cHV0czptLm91dHB1dHMsd2ViV29ya2VyOnV9fXZhciBVPV9yO3ZhciBmdD17bmFtZToiQGl0ay13YXNtL2RpY29tIix2ZXJzaW9uOiI1LjAuMCIsZGVzY3JpcHRpb246IlJlYWQgZmlsZXMgYW5kIGltYWdlcyByZWxhdGVkIHRvIERJQ09NIGZpbGUgZm9ybWF0LiIsdHlwZToibW9kdWxlIixtb2R1bGU6Ii4vZGlzdC9pbmRleC5qcyIsdHlwZXM6Ii4vZGlzdC9pbmRleC5kLnRzIixleHBvcnRzOnsiLiI6e3R5cGVzOiIuL2Rpc3QvaW5kZXguZC50cyIsYnJvd3NlcjoiLi9kaXN0L2luZGV4LmpzIixub2RlOiIuL2Rpc3QvaW5kZXgtbm9kZS5qcyIsZGVmYXVsdDoiLi9kaXN0L2luZGV4LmpzIn19LHNjcmlwdHM6e3N0YXJ0OiJucG0gcnVuIGNvcHlTaG9lbGFjZUFzc2V0cyAmJiB2aXRlIC1jIGJ1aWxkL3ZpdGUuY29uZmlnLmpzIix0ZXN0OiJucG0gcnVuIHRlc3Q6bm9kZSAmJiBucG0gcnVuIHRlc3Q6YnJvd3NlciIsInRlc3Q6bm9kZSI6ImF2YSB0ZXN0L25vZGUvKi5qcyIsInRlc3Q6YnJvd3NlciI6Im5wbSBydW4gdGVzdDpicm93c2VyOmNocm9tZSAmJiBucG0gcnVuIHRlc3Q6YnJvd3NlcjpmaXJlZm94IiwidGVzdDpicm93c2VyOmZpcmVmb3giOiJzdGFydC1zZXJ2ZXItYW5kLXRlc3Qgc3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTE3MyBjeXByZXNzOnJ1bkZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6Y2hyb21lIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHN0YXJ0IGh0dHAtZ2V0Oi8vbG9jYWxob3N0OjUxNzMgY3lwcmVzczpydW5DaHJvbWUiLCJ0ZXN0OmJyb3dzZXI6ZGVidWciOiJzdGFydC1zZXJ2ZXItYW5kLXRlc3Qgc3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTE3MyBjeXByZXNzOm9wZW4iLGNvcHlTaG9lbGFjZUFzc2V0czoic2h4IG1rZGlyIC1wIHRlc3QvYnJvd3Nlci9kZW1vLWFwcC9wdWJsaWMvc2hvZWxhY2UgJiYgc2h4IGNwIC1yIG5vZGVfbW9kdWxlcy9Ac2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UvZGlzdC9hc3NldHMgdGVzdC9icm93c2VyL2RlbW8tYXBwL3B1YmxpYy8iLCJjeXByZXNzOm9wZW4iOiJucHggY3lwcmVzcyBvcGVuIiwiY3lwcmVzczpydW5DaHJvbWUiOiJucHggY3lwcmVzcyBydW4gLS1icm93c2VyIGNocm9tZSIsImN5cHJlc3M6cnVuRmlyZWZveCI6Im5weCBjeXByZXNzIHJ1biAtLWJyb3dzZXIgZmlyZWZveCIsYnVpbGQ6Im5wbSBydW4gYnVpbGQ6dHNjICYmIG5wbSBydW4gYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZCAmJiBucG0gcnVuIGJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWRNaW4gJiYgbnBtIHJ1biBidWlsZDpkZW1vIiwiYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZCI6ImVzYnVpbGQgLS1sb2FkZXI6Lndvcmtlci5qcz1kYXRhdXJsIC0tYnVuZGxlIC0tZm9ybWF0PWVzbSAtLW91dGZpbGU9Li9kaXN0L2J1bmRsZS9pbmRleC13b3JrZXItZW1iZWRkZWQuanMgLi9zcmMvaW5kZXgtd29ya2VyLWVtYmVkZGVkLnRzIiwiYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZE1pbiI6ImVzYnVpbGQgLS1taW5pZnkgLS1sb2FkZXI6Lndvcmtlci5qcz1kYXRhdXJsIC0tYnVuZGxlIC0tZm9ybWF0PWVzbSAtLW91dGZpbGU9Li9kaXN0L2J1bmRsZS9pbmRleC13b3JrZXItZW1iZWRkZWQubWluLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC5taW4udHMiLCJidWlsZDp0c2MiOiJ0c2MgLS1wcmV0dHkiLCJidWlsZDpkZW1vIjoibnBtIHJ1biBjb3B5U2hvZWxhY2VBc3NldHMgJiYgdml0ZSAtYyBidWlsZC92aXRlLmNvbmZpZy5qcyBidWlsZCJ9LGtleXdvcmRzOlsiaXRrIiwid2FzbSIsIndlYmFzc2VtYmx5Il0sYXV0aG9yOiIiLGxpY2Vuc2U6IkFwYWNoZS0yLjAiLGRlcGVuZGVuY2llczp7Iml0ay13YXNtIjoiXjEuMC4wLWIuMTU0In0sZGV2RGVwZW5kZW5jaWVzOnsiQGl0ay13YXNtL2ltYWdlLWlvIjoiXjAuNC4wIiwiQHNob2VsYWNlLXN0eWxlL3Nob2VsYWNlIjoiXjIuNS4yIiwiQHR5cGVzL25vZGUiOiJeMjAuMi41IixhdmE6Il41LjEuMCIsY3lwcmVzczoiXjEyLjE3LjIiLHNoeDoiXjAuMy40Iiwic3RhcnQtc2VydmVyLWFuZC10ZXN0IjoiXjIuMC4wIix0eXBlc2NyaXB0OiJeNS4xLjYiLHZpdGU6Il40LjQuMTEiLCJ2aXRlLXBsdWdpbi1zdGF0aWMtY29weSI6Il4wLjE3LjAifSxyZXBvc2l0b3J5Ont0eXBlOiJnaXQiLHVybDoiaHR0cHM6Ly9naXRodWIuY29tL0luc2lnaHRTb2Z0d2FyZUNvbnNvcnRpdW0vaXRrLXdhc20ifX07dmFyIGllLFZyPWBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL0BpdGstd2FzbS9kaWNvbUAke2Z0LnZlcnNpb259L2Rpc3QvcGlwZWxpbmVzYDtmdW5jdGlvbiBJcyhBKXtpZT1BfWZ1bmN0aW9uIE8oKXtpZih0eXBlb2YgaWU8InUiKXJldHVybiBpZTtsZXQgQT1udCgpO3JldHVybiB0eXBlb2YgQTwidSI/QTpWcn12YXIgYWUsWnI9bnVsbDtmdW5jdGlvbiB1dChBKXthZT1BfWZ1bmN0aW9uIFQoKXtpZih0eXBlb2YgYWU8InUiKXJldHVybiBhZTtsZXQgQT1ydCgpO3JldHVybiB0eXBlb2YgQTwidSI/QTpacn1hc3luYyBmdW5jdGlvbiBYcihBLHQsZSxyPXt9KXtsZXQgbj1be3R5cGU6RS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6RS5JbWFnZX1dLGE9dDtpZih0IGluc3RhbmNlb2YgRmlsZSl7bGV0IGg9YXdhaXQgdC5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6dC5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoaCl9fWxldCBpPWU7aWYoZSBpbnN0YW5jZW9mIEZpbGUpe2xldCBoPWF3YWl0IGUuYXJyYXlCdWZmZXIoKTtpPXtwYXRoOmUubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KGgpfX1sZXQgbD1be3R5cGU6RS5CaW5hcnlGaWxlLGRhdGE6YX0se3R5cGU6RS5CaW5hcnlGaWxlLGRhdGE6aX1dLHU9W10sbz1hLnBhdGg7dS5wdXNoKG8pO2xldCBzPWkucGF0aDt1LnB1c2gocyk7bGV0IEM9IjAiO3UucHVzaChDKTtsZXQgYz0iMSI7dS5wdXNoKGMpLHUucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5jb2xvck91dHB1dDwidSImJnIuY29sb3JPdXRwdXQmJnUucHVzaCgiLS1jb2xvci1vdXRwdXQiKSx0eXBlb2Ygci5jb25maWdGaWxlPCJ1IiYmdS5wdXNoKCItLWNvbmZpZy1maWxlIixyLmNvbmZpZ0ZpbGUudG9TdHJpbmcoKSksdHlwZW9mIHIuZnJhbWU8InUiJiZ1LnB1c2goIi0tZnJhbWUiLHIuZnJhbWUudG9TdHJpbmcoKSksdHlwZW9mIHIubm9QcmVzZW50YXRpb25TdGF0ZU91dHB1dDwidSImJnIubm9QcmVzZW50YXRpb25TdGF0ZU91dHB1dCYmdS5wdXNoKCItLW5vLXByZXNlbnRhdGlvbi1zdGF0ZS1vdXRwdXQiKSx0eXBlb2Ygci5ub0JpdG1hcE91dHB1dDwidSImJnIubm9CaXRtYXBPdXRwdXQmJnUucHVzaCgiLS1uby1iaXRtYXAtb3V0cHV0Iik7bGV0IEk9ImFwcGx5LXByZXNlbnRhdGlvbi1zdGF0ZS10by1pbWFnZSIse3dlYldvcmtlcjpmLHJldHVyblZhbHVlOkIsc3RkZXJyOnAsb3V0cHV0czptfT1hd2FpdCBVKEEsSSx1LG4sbCx7cGlwZWxpbmVCYXNlVXJsOk8oKSxwaXBlbGluZVdvcmtlclVybDpUKCl9KTtpZihCIT09MCYmcCE9PSIiKXRocm93IG5ldyBFcnJvcihwKTtyZXR1cm57d2ViV29ya2VyOmYscHJlc2VudGF0aW9uU3RhdGVPdXRTdHJlYW06bVswXT8uZGF0YSxvdXRwdXRJbWFnZTptWzFdPy5kYXRhfX12YXIgJHI9WHI7YXN5bmMgZnVuY3Rpb24gQW4oQSx0LGU9e30pe2xldCByPVt7dHlwZTpFLkJpbmFyeVN0cmVhbX1dLG49dDtpZih0IGluc3RhbmNlb2YgRmlsZSl7bGV0IEI9YXdhaXQgdC5hcnJheUJ1ZmZlcigpO249e3BhdGg6dC5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoQil9fWxldCBhPVt7dHlwZTpFLkJpbmFyeUZpbGUsZGF0YTpufV0saT1bXSxsPW4ucGF0aDtpLnB1c2gobCk7bGV0IHU9IjAiO2kucHVzaCh1KSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIGUucmVhZEZpbGVPbmx5PCJ1IiYmZS5yZWFkRmlsZU9ubHkmJmkucHVzaCgiLS1yZWFkLWZpbGUtb25seSIpLHR5cGVvZiBlLnJlYWREYXRhc2V0PCJ1IiYmZS5yZWFkRGF0YXNldCYmaS5wdXNoKCItLXJlYWQtZGF0YXNldCIpLHR5cGVvZiBlLnJlYWRYZmVyQXV0bzwidSImJmUucmVhZFhmZXJBdXRvJiZpLnB1c2goIi0tcmVhZC14ZmVyLWF1dG8iKSx0eXBlb2YgZS5yZWFkWGZlckRldGVjdDwidSImJmUucmVhZFhmZXJEZXRlY3QmJmkucHVzaCgiLS1yZWFkLXhmZXItZGV0ZWN0IiksdHlwZW9mIGUucmVhZFhmZXJMaXR0bGU8InUiJiZlLnJlYWRYZmVyTGl0dGxlJiZpLnB1c2goIi0tcmVhZC14ZmVyLWxpdHRsZSIpLHR5cGVvZiBlLnJlYWRYZmVyQmlnPCJ1IiYmZS5yZWFkWGZlckJpZyYmaS5wdXNoKCItLXJlYWQteGZlci1iaWciKSx0eXBlb2YgZS5yZWFkWGZlckltcGxpY2l0PCJ1IiYmZS5yZWFkWGZlckltcGxpY2l0JiZpLnB1c2goIi0tcmVhZC14ZmVyLWltcGxpY2l0IiksdHlwZW9mIGUuYWNjZXB0T2RkTGVuZ3RoPCJ1IiYmZS5hY2NlcHRPZGRMZW5ndGgmJmkucHVzaCgiLS1hY2NlcHQtb2RkLWxlbmd0aCIpLHR5cGVvZiBlLmFzc3VtZUV2ZW5MZW5ndGg8InUiJiZlLmFzc3VtZUV2ZW5MZW5ndGgmJmkucHVzaCgiLS1hc3N1bWUtZXZlbi1sZW5ndGgiKSx0eXBlb2YgZS5lbmFibGVDcDI0NjwidSImJmUuZW5hYmxlQ3AyNDYmJmkucHVzaCgiLS1lbmFibGUtY3AyNDYiKSx0eXBlb2YgZS5kaXNhYmxlQ3AyNDY8InUiJiZlLmRpc2FibGVDcDI0NiYmaS5wdXNoKCItLWRpc2FibGUtY3AyNDYiKSx0eXBlb2YgZS5yZXRhaW5VbjwidSImJmUucmV0YWluVW4mJmkucHVzaCgiLS1yZXRhaW4tdW4iKSx0eXBlb2YgZS5jb252ZXJ0VW48InUiJiZlLmNvbnZlcnRVbiYmaS5wdXNoKCItLWNvbnZlcnQtdW4iKSx0eXBlb2YgZS5lbmFibGVDb3JyZWN0aW9uPCJ1IiYmZS5lbmFibGVDb3JyZWN0aW9uJiZpLnB1c2goIi0tZW5hYmxlLWNvcnJlY3Rpb24iKSx0eXBlb2YgZS5kaXNhYmxlQ29ycmVjdGlvbjwidSImJmUuZGlzYWJsZUNvcnJlY3Rpb24mJmkucHVzaCgiLS1kaXNhYmxlLWNvcnJlY3Rpb24iKTtsZXQgbz0icmVhZC1kaWNvbS1lbmNhcHN1bGF0ZWQtcGRmIix7d2ViV29ya2VyOnMscmV0dXJuVmFsdWU6QyxzdGRlcnI6YyxvdXRwdXRzOkl9PWF3YWl0IFUoQSxvLGkscixhLHtwaXBlbGluZUJhc2VVcmw6TygpLHBpcGVsaW5lV29ya2VyVXJsOlQoKX0pO2lmKEMhPT0wJiZjIT09IiIpdGhyb3cgbmV3IEVycm9yKGMpO3JldHVybnt3ZWJXb3JrZXI6cyxwZGZCaW5hcnlPdXRwdXQ6KElbMF0/LmRhdGEpLmRhdGF9fXZhciBlbj1Bbjthc3luYyBmdW5jdGlvbiB0bihBLHQsZT17fSl7bGV0IHI9W3t0eXBlOkUuVGV4dFN0cmVhbX1dLG49dDtpZih0IGluc3RhbmNlb2YgRmlsZSl7bGV0IEI9YXdhaXQgdC5hcnJheUJ1ZmZlcigpO249e3BhdGg6dC5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoQil9fWxldCBhPVt7dHlwZTpFLkJpbmFyeUZpbGUsZGF0YTpufV0saT1bXSxsPW4ucGF0aDtpLnB1c2gobCk7bGV0IHU9IjAiO2lmKGkucHVzaCh1KSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIGUucmVhZEZpbGVPbmx5PCJ1IiYmZS5yZWFkRmlsZU9ubHkmJmkucHVzaCgiLS1yZWFkLWZpbGUtb25seSIpLHR5cGVvZiBlLnJlYWREYXRhc2V0PCJ1IiYmZS5yZWFkRGF0YXNldCYmaS5wdXNoKCItLXJlYWQtZGF0YXNldCIpLHR5cGVvZiBlLnJlYWRYZmVyQXV0bzwidSImJmUucmVhZFhmZXJBdXRvJiZpLnB1c2goIi0tcmVhZC14ZmVyLWF1dG8iKSx0eXBlb2YgZS5yZWFkWGZlckRldGVjdDwidSImJmUucmVhZFhmZXJEZXRlY3QmJmkucHVzaCgiLS1yZWFkLXhmZXItZGV0ZWN0IiksdHlwZW9mIGUucmVhZFhmZXJMaXR0bGU8InUiJiZlLnJlYWRYZmVyTGl0dGxlJiZpLnB1c2goIi0tcmVhZC14ZmVyLWxpdHRsZSIpLHR5cGVvZiBlLnJlYWRYZmVyQmlnPCJ1IiYmZS5yZWFkWGZlckJpZyYmaS5wdXNoKCItLXJlYWQteGZlci1iaWciKSx0eXBlb2YgZS5yZWFkWGZlckltcGxpY2l0PCJ1IiYmZS5yZWFkWGZlckltcGxpY2l0JiZpLnB1c2goIi0tcmVhZC14ZmVyLWltcGxpY2l0IiksdHlwZW9mIGUucHJvY2Vzc2luZ0RldGFpbHM8InUiJiZlLnByb2Nlc3NpbmdEZXRhaWxzJiZpLnB1c2goIi0tcHJvY2Vzc2luZy1kZXRhaWxzIiksdHlwZW9mIGUudW5rbm93blJlbGF0aW9uc2hpcDwidSImJmUudW5rbm93blJlbGF0aW9uc2hpcCYmaS5wdXNoKCItLXVua25vd24tcmVsYXRpb25zaGlwIiksdHlwZW9mIGUuaW52YWxpZEl0ZW1WYWx1ZTwidSImJmUuaW52YWxpZEl0ZW1WYWx1ZSYmaS5wdXNoKCItLWludmFsaWQtaXRlbS12YWx1ZSIpLHR5cGVvZiBlLmlnbm9yZUNvbnN0cmFpbnRzPCJ1IiYmZS5pZ25vcmVDb25zdHJhaW50cyYmaS5wdXNoKCItLWlnbm9yZS1jb25zdHJhaW50cyIpLHR5cGVvZiBlLmlnbm9yZUl0ZW1FcnJvcnM8InUiJiZlLmlnbm9yZUl0ZW1FcnJvcnMmJmkucHVzaCgiLS1pZ25vcmUtaXRlbS1lcnJvcnMiKSx0eXBlb2YgZS5za2lwSW52YWxpZEl0ZW1zPCJ1IiYmZS5za2lwSW52YWxpZEl0ZW1zJiZpLnB1c2goIi0tc2tpcC1pbnZhbGlkLWl0ZW1zIiksdHlwZW9mIGUuZGlzYWJsZVZyQ2hlY2tlcjwidSImJmUuZGlzYWJsZVZyQ2hlY2tlciYmaS5wdXNoKCItLWRpc2FibGUtdnItY2hlY2tlciIpLHR5cGVvZiBlLmNoYXJzZXRSZXF1aXJlPCJ1IiYmZS5jaGFyc2V0UmVxdWlyZSYmaS5wdXNoKCItLWNoYXJzZXQtcmVxdWlyZSIpLHR5cGVvZiBlLmNoYXJzZXRBc3N1bWU8InUiJiZpLnB1c2goIi0tY2hhcnNldC1hc3N1bWUiLGUuY2hhcnNldEFzc3VtZS50b1N0cmluZygpKSx0eXBlb2YgZS5jaGFyc2V0Q2hlY2tBbGw8InUiJiZlLmNoYXJzZXRDaGVja0FsbCYmaS5wdXNoKCItLWNoYXJzZXQtY2hlY2stYWxsIiksdHlwZW9mIGUuY29udmVydFRvVXRmODwidSImJmUuY29udmVydFRvVXRmOCYmaS5wdXNoKCItLWNvbnZlcnQtdG8tdXRmOCIpLHR5cGVvZiBlLnVybFByZWZpeDwidSImJmkucHVzaCgiLS11cmwtcHJlZml4IixlLnVybFByZWZpeC50b1N0cmluZygpKSx0eXBlb2YgZS5odG1sMzI8InUiJiZlLmh0bWwzMiYmaS5wdXNoKCItLWh0bWwtMzIiKSx0eXBlb2YgZS5odG1sNDA8InUiJiZlLmh0bWw0MCYmaS5wdXNoKCItLWh0bWwtNDAiKSx0eXBlb2YgZS54aHRtbDExPCJ1IiYmZS54aHRtbDExJiZpLnB1c2goIi0teGh0bWwtMTEiKSx0eXBlb2YgZS5hZGREb2N1bWVudFR5cGU8InUiJiZlLmFkZERvY3VtZW50VHlwZSYmaS5wdXNoKCItLWFkZC1kb2N1bWVudC10eXBlIiksdHlwZW9mIGUuY3NzUmVmZXJlbmNlPCJ1Iil7bGV0IEI9YS5sZW5ndGgudG9TdHJpbmcoKTthLnB1c2goe3R5cGU6RS5UZXh0U3RyZWFtLGRhdGE6e2RhdGE6ZS5jc3NSZWZlcmVuY2V9fSksaS5wdXNoKCItLWNzcy1yZWZlcmVuY2UiLEIpfWlmKHR5cGVvZiBlLmNzc0ZpbGU8InUiKXtsZXQgQj1lLmNzc0ZpbGUscD1CO2lmKEIgaW5zdGFuY2VvZiBGaWxlKXtsZXQgUT1hd2FpdCBCLmFycmF5QnVmZmVyKCk7cD17cGF0aDpCLm5hbWUsZGF0YTpuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoUSl9fWkucHVzaCgiLS1jc3MtZmlsZSIpLGEucHVzaCh7dHlwZTpFLlRleHRGaWxlLGRhdGE6cH0pO2xldCBtPUIgaW5zdGFuY2VvZiBGaWxlP0IubmFtZTpCLnBhdGg7aS5wdXNoKG0pfXR5cGVvZiBlLmV4cGFuZElubGluZTwidSImJmUuZXhwYW5kSW5saW5lJiZpLnB1c2goIi0tZXhwYW5kLWlubGluZSIpLHR5cGVvZiBlLm5ldmVyRXhwYW5kSW5saW5lPCJ1IiYmZS5uZXZlckV4cGFuZElubGluZSYmaS5wdXNoKCItLW5ldmVyLWV4cGFuZC1pbmxpbmUiKSx0eXBlb2YgZS5hbHdheXNFeHBhbmRJbmxpbmU8InUiJiZlLmFsd2F5c0V4cGFuZElubGluZSYmaS5wdXNoKCItLWFsd2F5cy1leHBhbmQtaW5saW5lIiksdHlwZW9mIGUucmVuZGVyRnVsbERhdGE8InUiJiZlLnJlbmRlckZ1bGxEYXRhJiZpLnB1c2goIi0tcmVuZGVyLWZ1bGwtZGF0YSIpLHR5cGVvZiBlLnNlY3Rpb25UaXRsZUlubGluZTwidSImJmUuc2VjdGlvblRpdGxlSW5saW5lJiZpLnB1c2goIi0tc2VjdGlvbi10aXRsZS1pbmxpbmUiKSx0eXBlb2YgZS5kb2N1bWVudFR5cGVUaXRsZTwidSImJmUuZG9jdW1lbnRUeXBlVGl0bGUmJmkucHVzaCgiLS1kb2N1bWVudC10eXBlLXRpdGxlIiksdHlwZW9mIGUucGF0aWVudEluZm9UaXRsZTwidSImJmUucGF0aWVudEluZm9UaXRsZSYmaS5wdXNoKCItLXBhdGllbnQtaW5mby10aXRsZSIpLHR5cGVvZiBlLm5vRG9jdW1lbnRIZWFkZXI8InUiJiZlLm5vRG9jdW1lbnRIZWFkZXImJmkucHVzaCgiLS1uby1kb2N1bWVudC1oZWFkZXIiKSx0eXBlb2YgZS5yZW5kZXJJbmxpbmVDb2RlczwidSImJmUucmVuZGVySW5saW5lQ29kZXMmJmkucHVzaCgiLS1yZW5kZXItaW5saW5lLWNvZGVzIiksdHlwZW9mIGUuY29uY2VwdE5hbWVDb2RlczwidSImJmUuY29uY2VwdE5hbWVDb2RlcyYmaS5wdXNoKCItLWNvbmNlcHQtbmFtZS1jb2RlcyIpLHR5cGVvZiBlLm51bWVyaWNVbml0Q29kZXM8InUiJiZlLm51bWVyaWNVbml0Q29kZXMmJmkucHVzaCgiLS1udW1lcmljLXVuaXQtY29kZXMiKSx0eXBlb2YgZS5jb2RlVmFsdWVVbml0PCJ1IiYmZS5jb2RlVmFsdWVVbml0JiZpLnB1c2goIi0tY29kZS12YWx1ZS11bml0IiksdHlwZW9mIGUuY29kZU1lYW5pbmdVbml0PCJ1IiYmZS5jb2RlTWVhbmluZ1VuaXQmJmkucHVzaCgiLS1jb2RlLW1lYW5pbmctdW5pdCIpLHR5cGVvZiBlLnJlbmRlckFsbENvZGVzPCJ1IiYmZS5yZW5kZXJBbGxDb2RlcyYmaS5wdXNoKCItLXJlbmRlci1hbGwtY29kZXMiKSx0eXBlb2YgZS5jb2RlRGV0YWlsc1Rvb2x0aXA8InUiJiZlLmNvZGVEZXRhaWxzVG9vbHRpcCYmaS5wdXNoKCItLWNvZGUtZGV0YWlscy10b29sdGlwIik7bGV0IG89InN0cnVjdHVyZWQtcmVwb3J0LXRvLWh0bWwiLHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTpDLHN0ZGVycjpjLG91dHB1dHM6SX09YXdhaXQgVShBLG8saSxyLGEse3BpcGVsaW5lQmFzZVVybDpPKCkscGlwZWxpbmVXb3JrZXJVcmw6VCgpfSk7aWYoQyE9PTAmJmMhPT0iIil0aHJvdyBuZXcgRXJyb3IoYyk7cmV0dXJue3dlYldvcmtlcjpzLG91dHB1dFRleHQ6KElbMF0/LmRhdGEpLmRhdGF9fXZhciBybj10bjthc3luYyBmdW5jdGlvbiBubihBLHQsZT17fSl7bGV0IHI9W3t0eXBlOkUuVGV4dFN0cmVhbX1dLG49dDtpZih0IGluc3RhbmNlb2YgRmlsZSl7bGV0IEI9YXdhaXQgdC5hcnJheUJ1ZmZlcigpO249e3BhdGg6dC5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoQil9fWxldCBhPVt7dHlwZTpFLkJpbmFyeUZpbGUsZGF0YTpufV0saT1bXSxsPW4ucGF0aDtpLnB1c2gobCk7bGV0IHU9IjAiO2kucHVzaCh1KSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIGUudW5rbm93blJlbGF0aW9uc2hpcDwidSImJmUudW5rbm93blJlbGF0aW9uc2hpcCYmaS5wdXNoKCItLXVua25vd24tcmVsYXRpb25zaGlwIiksdHlwZW9mIGUuaW52YWxpZEl0ZW1WYWx1ZTwidSImJmUuaW52YWxpZEl0ZW1WYWx1ZSYmaS5wdXNoKCItLWludmFsaWQtaXRlbS12YWx1ZSIpLHR5cGVvZiBlLmlnbm9yZUNvbnN0cmFpbnRzPCJ1IiYmZS5pZ25vcmVDb25zdHJhaW50cyYmaS5wdXNoKCItLWlnbm9yZS1jb25zdHJhaW50cyIpLHR5cGVvZiBlLmlnbm9yZUl0ZW1FcnJvcnM8InUiJiZlLmlnbm9yZUl0ZW1FcnJvcnMmJmkucHVzaCgiLS1pZ25vcmUtaXRlbS1lcnJvcnMiKSx0eXBlb2YgZS5za2lwSW52YWxpZEl0ZW1zPCJ1IiYmZS5za2lwSW52YWxpZEl0ZW1zJiZpLnB1c2goIi0tc2tpcC1pbnZhbGlkLWl0ZW1zIiksdHlwZW9mIGUubm9Eb2N1bWVudEhlYWRlcjwidSImJmUubm9Eb2N1bWVudEhlYWRlciYmaS5wdXNoKCItLW5vLWRvY3VtZW50LWhlYWRlciIpLHR5cGVvZiBlLm51bWJlck5lc3RlZEl0ZW1zPCJ1IiYmZS5udW1iZXJOZXN0ZWRJdGVtcyYmaS5wdXNoKCItLW51bWJlci1uZXN0ZWQtaXRlbXMiKSx0eXBlb2YgZS5zaG9ydGVuTG9uZ1ZhbHVlczwidSImJmUuc2hvcnRlbkxvbmdWYWx1ZXMmJmkucHVzaCgiLS1zaG9ydGVuLWxvbmctdmFsdWVzIiksdHlwZW9mIGUucHJpbnRJbnN0YW5jZVVpZDwidSImJmUucHJpbnRJbnN0YW5jZVVpZCYmaS5wdXNoKCItLXByaW50LWluc3RhbmNlLXVpZCIpLHR5cGVvZiBlLnByaW50U29wY2xhc3NTaG9ydDwidSImJmUucHJpbnRTb3BjbGFzc1Nob3J0JiZpLnB1c2goIi0tcHJpbnQtc29wY2xhc3Mtc2hvcnQiKSx0eXBlb2YgZS5wcmludFNvcGNsYXNzTG9uZzwidSImJmUucHJpbnRTb3BjbGFzc0xvbmcmJmkucHVzaCgiLS1wcmludC1zb3BjbGFzcy1sb25nIiksdHlwZW9mIGUucHJpbnRTb3BjbGFzc1VpZDwidSImJmUucHJpbnRTb3BjbGFzc1VpZCYmaS5wdXNoKCItLXByaW50LXNvcGNsYXNzLXVpZCIpLHR5cGVvZiBlLnByaW50QWxsQ29kZXM8InUiJiZlLnByaW50QWxsQ29kZXMmJmkucHVzaCgiLS1wcmludC1hbGwtY29kZXMiKSx0eXBlb2YgZS5wcmludEludmFsaWRDb2RlczwidSImJmUucHJpbnRJbnZhbGlkQ29kZXMmJmkucHVzaCgiLS1wcmludC1pbnZhbGlkLWNvZGVzIiksdHlwZW9mIGUucHJpbnRUZW1wbGF0ZUlkPCJ1IiYmZS5wcmludFRlbXBsYXRlSWQmJmkucHVzaCgiLS1wcmludC10ZW1wbGF0ZS1pZCIpLHR5cGVvZiBlLmluZGljYXRlRW5oYW5jZWQ8InUiJiZlLmluZGljYXRlRW5oYW5jZWQmJmkucHVzaCgiLS1pbmRpY2F0ZS1lbmhhbmNlZCIpLHR5cGVvZiBlLnByaW50Q29sb3I8InUiJiZlLnByaW50Q29sb3ImJmkucHVzaCgiLS1wcmludC1jb2xvciIpO2xldCBvPSJzdHJ1Y3R1cmVkLXJlcG9ydC10by10ZXh0Iix7d2ViV29ya2VyOnMscmV0dXJuVmFsdWU6QyxzdGRlcnI6YyxvdXRwdXRzOkl9PWF3YWl0IFUoQSxvLGkscixhLHtwaXBlbGluZUJhc2VVcmw6TygpLHBpcGVsaW5lV29ya2VyVXJsOlQoKX0pO2lmKEMhPT0wJiZjIT09IiIpdGhyb3cgbmV3IEVycm9yKGMpO3JldHVybnt3ZWJXb3JrZXI6cyxvdXRwdXRUZXh0OihJWzBdPy5kYXRhKS5kYXRhfX12YXIgYW49bm47YXN5bmMgZnVuY3Rpb24gb24oQSx0LGU9e30pe2xldCByPVt7dHlwZTpFLkpzb25Db21wYXRpYmxlfV0sbj10O2lmKHQgaW5zdGFuY2VvZiBGaWxlKXtsZXQgQj1hd2FpdCB0LmFycmF5QnVmZmVyKCk7bj17cGF0aDp0Lm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShCKX19bGV0IGE9W3t0eXBlOkUuQmluYXJ5RmlsZSxkYXRhOm59XSxpPVtdLGw9bi5wYXRoO2kucHVzaChsKTtsZXQgdT0iMCI7aWYoaS5wdXNoKHUpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgZS50YWdzVG9SZWFkPCJ1Iil7bGV0IEI9YS5sZW5ndGgudG9TdHJpbmcoKTthLnB1c2goe3R5cGU6RS5Kc29uQ29tcGF0aWJsZSxkYXRhOmUudGFnc1RvUmVhZH0pLGkucHVzaCgiLS10YWdzLXRvLXJlYWQiLEIpfWxldCBvPSJyZWFkLWRpY29tLXRhZ3MiLHt3ZWJXb3JrZXI6cyxyZXR1cm5WYWx1ZTpDLHN0ZGVycjpjLG91dHB1dHM6SX09YXdhaXQgVShBLG8saSxyLGEse3BpcGVsaW5lQmFzZVVybDpPKCkscGlwZWxpbmVXb3JrZXJVcmw6VCgpfSk7aWYoQyE9PTApdGhyb3cgbmV3IEVycm9yKGMpO3JldHVybnt3ZWJXb3JrZXI6cyx0YWdzOklbMF0uZGF0YX19dmFyIHNuPW9uO2FzeW5jIGZ1bmN0aW9uIEluKEEsdCxlPSExKXtsZXQgcj1be3R5cGU6RS5JbWFnZX0se3R5cGU6RS5Kc29uQ29tcGF0aWJsZX1dLG49W10sYT1bXSxpPSIwIjthLnB1c2goaSk7bGV0IGw9IjEiO2EucHVzaChsKSxhLnB1c2goIi0tbWVtb3J5LWlvIiksYS5wdXNoKCItLWlucHV0LWltYWdlcyIpLHQuZm9yRWFjaChmPT57bi5wdXNoKHt0eXBlOkUuQmluYXJ5RmlsZSxkYXRhOmZ9KSxhLnB1c2goZi5wYXRoKX0pLHR5cGVvZiBlPCJ1IiYmZSYmYS5wdXNoKCItLXNpbmdsZS1zb3J0ZWQtc2VyaWVzIik7bGV0IHU9InJlYWQtaW1hZ2UtZGljb20tZmlsZS1zZXJpZXMiLHt3ZWJXb3JrZXI6byxyZXR1cm5WYWx1ZTpzLHN0ZGVycjpDLG91dHB1dHM6Y309YXdhaXQgVShBLHUsYSxyLG4se3BpcGVsaW5lQmFzZVVybDpPKCkscGlwZWxpbmVXb3JrZXJVcmw6VCgpfSk7aWYocyE9PTApdGhyb3cgbmV3IEVycm9yKEMpO3JldHVybnt3ZWJXb3JrZXI6byxvdXRwdXRJbWFnZTpjWzBdLmRhdGEsc29ydGVkRmlsZW5hbWVzOmNbMV0uZGF0YX19dmFyIG9lPUluO3ZhciBnbj10eXBlb2YgZ2xvYmFsVGhpcy5uYXZpZ2F0b3I/LmhhcmR3YXJlQ29uY3VycmVuY3k9PSJudW1iZXIiP2dsb2JhbFRoaXMubmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3k6NCxDdD04O2FzeW5jIGZ1bmN0aW9uIGxuKEEsdD17aW5wdXRJbWFnZXM6W119KXtsZXQgZT1BO2U9PT1udWxsJiYoZT1uZXcgTkEoZ24sb2UpKTtsZXQgcj1bXTtpZih0LmlucHV0SW1hZ2VzLmxlbmd0aDwxKXRocm93IG5ldyBFcnJvcignImlucHV0LWltYWdlcyIgb3B0aW9uIG11c3QgaGF2ZSBhIGxlbmd0aCA+IDEnKTtpZihhd2FpdCBQcm9taXNlLmFsbCh0LmlucHV0SW1hZ2VzLm1hcChhc3luYyBuPT57bGV0IGE9bjtpZihuIGluc3RhbmNlb2YgRmlsZSl7bGV0IGk9YXdhaXQgbi5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6bi5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoaSl9fXIucHVzaChhKX0pKSx0LnNpbmdsZVNvcnRlZFNlcmllcyl7bGV0IG49W107Zm9yKGxldCBvPTA7bzxyLmxlbmd0aDtvKz1DdCl7bGV0IHM9ci5zbGljZShvLG8rQ3QpO24ucHVzaChbcyx0LnNpbmdsZVNvcnRlZFNlcmllc10pfWxldCBhPWF3YWl0IGUucnVuVGFza3MobikucHJvbWlzZSxpPWEubWFwKG89Pm8ub3V0cHV0SW1hZ2UpLGw9YS5yZWR1Y2UoKG8scyk9Pm8uY29uY2F0KHMuc29ydGVkRmlsZW5hbWVzKSxbXSk7cmV0dXJue291dHB1dEltYWdlOlJBKGkpLHdlYldvcmtlclBvb2w6ZSxzb3J0ZWRGaWxlbmFtZXM6bH19ZWxzZXtsZXQgbj1bW3IsdC5zaW5nbGVTb3J0ZWRTZXJpZXNdXSxhPWF3YWl0IGUucnVuVGFza3MobikucHJvbWlzZTtyZXR1cm57b3V0cHV0SW1hZ2U6YVswXS5vdXRwdXRJbWFnZSx3ZWJXb3JrZXJQb29sOmUsc29ydGVkRmlsZW5hbWVzOmFbMF0uc29ydGVkRmlsZW5hbWVzfX19dmFyIGNuPWxuO3ZhciBCdD0nZGF0YTp0ZXh0L2phdmFzY3JpcHQ7Y2hhcnNldD11dGYtOCx2YXIgY2U9U3ltYm9sKCJDb21saW5rLnByb3h5IiksQ3Q9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IiksQnQ9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLE1BPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksZmU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsUXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmQVtjZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gRUEoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLGx0KEEpfX0sRXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LGxlPW5ldyBNYXAoW1sicHJveHkiLFF0XSxbInRocm93IixFdF1dKTtmdW5jdGlvbiBjdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gRUEoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBJKHIpe2lmKCFyfHwhci5kYXRhKXJldHVybjtpZighY3QodCxyLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gXCcke3Iub3JpZ2lufVwnIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6ZyxwYXRoOm59PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksRT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChxKSxvO3RyeXtsZXQgQj1uLnNsaWNlKDAsLTEpLnJlZHVjZSgoYSxDKT0+YVtDXSxBKSxjPW4ucmVkdWNlKChhLEMpPT5hW0NdLEEpO3N3aXRjaChnKXtjYXNlIkdFVCI6bz1jO2JyZWFrO2Nhc2UiU0VUIjpCW24uc2xpY2UoLTEpWzBdXT1xKHIuZGF0YS52YWx1ZSksbz0hMDticmVhaztjYXNlIkFQUExZIjpvPWMuYXBwbHkoQixFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBhPW5ldyBjKC4uLkUpO289bXQoYSl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTphLHBvcnQyOkN9PW5ldyBNZXNzYWdlQ2hhbm5lbDtFQShBLEMpLG89SEEoYSxbYV0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6bz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKEIpe289e3ZhbHVlOkIsW3NBXTowfX1Qcm9taXNlLnJlc29sdmUobykuY2F0Y2goQj0+KHt2YWx1ZTpCLFtzQV06MH0pKS50aGVuKEI9PntsZXRbYyxhXT1RQShCKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLGEpLGc9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLHVlKGUpLE1BIGluIEEmJnR5cGVvZiBBW01BXT09ImZ1bmN0aW9uIiYmQVtNQV0oKSl9KS5jYXRjaChCPT57bGV0W2MsYV09UUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtzQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LGMpLHtpZDppfSksYSl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBmdChBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiB1ZShBKXtmdChBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGx0KEEsZSl7cmV0dXJuIGJBKEEsW10sZSl9ZnVuY3Rpb24gYUEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIGhlKEEpe3JldHVybiB4KEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e3VlKEEpfSl9dmFyIENBPW5ldyBXZWFrTWFwLEJBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPShDQS5nZXQoQSl8fDApLTE7Q0Euc2V0KEEsZSksZT09PTAmJmhlKEEpfSk7ZnVuY3Rpb24gdXQoQSxlKXtsZXQgdD0oQ0EuZ2V0KGUpfHwwKSsxO0NBLnNldChlLHQpLEJBJiZCQS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gaHQoQSl7QkEmJkJBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gYkEoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgST0hMSxyPW5ldyBQcm94eSh0LHtnZXQoaSxnKXtpZihhQShJKSxnPT09QnQpcmV0dXJuKCk9PntodChyKSxoZShBKSxJPSEwfTtpZihnPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9PnJ9O2xldCBuPXgoQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKEU9PkUudG9TdHJpbmcoKSl9KS50aGVuKHEpO3JldHVybiBuLnRoZW4uYmluZChuKX1yZXR1cm4gYkEoQSxbLi4uZSxnXSl9LHNldChpLGcsbil7YUEoSSk7bGV0W0Usb109UUEobik7cmV0dXJuIHgoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGddLm1hcChCPT5CLnRvU3RyaW5nKCkpLHZhbHVlOkV9LG8pLnRoZW4ocSl9LGFwcGx5KGksZyxuKXthQShJKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1DdClyZXR1cm4geChBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKHEpO2lmKEU9PT0iYmluZCIpcmV0dXJuIGJBKEEsZS5zbGljZSgwLC0xKSk7bGV0W28sQl09RWUobik7cmV0dXJuIHgoQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoYz0+Yy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6b30sQikudGhlbihxKX0sY29uc3RydWN0KGksZyl7YUEoSSk7bGV0W24sRV09RWUoZyk7cmV0dXJuIHgoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKG89Pm8udG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Om59LEUpLnRoZW4ocSl9fSk7cmV0dXJuIHV0KHIsQSkscn1mdW5jdGlvbiBkdChBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBFZShBKXtsZXQgZT1BLm1hcChRQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGR0KGUubWFwKHQ9PnRbMV0pKV19dmFyIGRlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIEhBKEEsZSl7cmV0dXJuIGRlLnNldChBLGUpLEF9ZnVuY3Rpb24gbXQoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W2NlXTohMH0pfWZ1bmN0aW9uIFFBKEEpe2ZvcihsZXRbZSx0XW9mIGxlKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZGUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gcShBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBsZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIHgoQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShJPT57bGV0IHI9RHQoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkoZyl7IWcuZGF0YXx8IWcuZGF0YS5pZHx8Zy5kYXRhLmlkIT09cnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSksSShnLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOnJ9LGUpLHQpfSl9ZnVuY3Rpb24gRHQoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIFgoQSxlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShlLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzp5dH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6VEF9PU9iamVjdCxmQT0oQT0+ZT0+e2xldCB0PXl0LmNhbGwoZSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxVPUE9PihBPUEudG9Mb3dlckNhc2UoKSxlPT5mQShlKT09PUEpLGxBPUE9PmU9PnR5cGVvZiBlPT09QSx7aXNBcnJheTpQfT1BcnJheSx2PWxBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiB3dChBKXtyZXR1cm4gQSE9PW51bGwmJiF2KEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIXYoQS5jb25zdHJ1Y3RvcikmJlIoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIHdlPVUoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gcHQoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZ3ZShBLmJ1ZmZlciksZX12YXIgRnQ9bEEoInN0cmluZyIpLFI9bEEoImZ1bmN0aW9uIikscGU9bEEoIm51bWJlciIpLHVBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsU3Q9QT0+QT09PSEwfHxBPT09ITEsY0E9QT0+e2lmKGZBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9VEEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sTnQ9VSgiRGF0ZSIpLFJ0PVUoIkZpbGUiKSxHdD1VKCJCbG9iIiksVXQ9VSgiRmlsZUxpc3QiKSxrdD1BPT51QShBKSYmUihBLnBpcGUpLEx0PUE9PntsZXQgZTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxSKEEuYXBwZW5kKSYmKChlPWZBKEEpKT09PSJmb3JtZGF0YSJ8fGU9PT0ib2JqZWN0IiYmUihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxPdD1VKCJVUkxTZWFyY2hQYXJhbXMiKSxKdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gJChBLGUse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBJLHI7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLFAoQSkpZm9yKEk9MCxyPUEubGVuZ3RoO0k8cjtJKyspZS5jYWxsKG51bGwsQVtJXSxJLEEpO2Vsc2V7bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxnPWkubGVuZ3RoLG47Zm9yKEk9MDtJPGc7SSsrKW49aVtJXSxlLmNhbGwobnVsbCxBW25dLG4sQSl9fWZ1bmN0aW9uIEZlKEEsZSl7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgU2U9KCgpPT50eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsKSgpLE5lPUE9PiF2KEEpJiZBIT09U2U7ZnVuY3Rpb24gcUEoKXtsZXR7Y2FzZWxlc3M6QX09TmUodGhpcykmJnRoaXN8fHt9LGU9e30sdD0oSSxyKT0+e2xldCBpPUEmJkZlKGUscil8fHI7Y0EoZVtpXSkmJmNBKEkpP2VbaV09cUEoZVtpXSxJKTpjQShJKT9lW2ldPXFBKHt9LEkpOlAoSSk/ZVtpXT1JLnNsaWNlKCk6ZVtpXT1JfTtmb3IobGV0IEk9MCxyPWFyZ3VtZW50cy5sZW5ndGg7STxyO0krKylhcmd1bWVudHNbSV0mJiQoYXJndW1lbnRzW0ldLHQpO3JldHVybiBlfXZhciBNdD0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4oJChlLChyLGkpPT57dCYmUihyKT9BW2ldPVgocix0KTpBW2ldPXJ9LHthbGxPd25LZXlzOkl9KSxBKSxidD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLEh0PShBLGUsdCxJKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZS5wcm90b3R5cGUsSSksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTplLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LFl0PShBLGUsdCxJKT0+e2xldCByLGksZyxuPXt9O2lmKGU9ZXx8e30sQT09bnVsbClyZXR1cm4gZTtkb3tmb3Iocj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxpPXIubGVuZ3RoO2ktLSA+MDspZz1yW2ldLCghSXx8SShnLEEsZSkpJiYhbltnXSYmKGVbZ109QVtnXSxuW2ddPSEwKTtBPXQhPT0hMSYmVEEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsZSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIGV9LHF0PShBLGUsdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1lLmxlbmd0aDtsZXQgST1BLmluZGV4T2YoZSx0KTtyZXR1cm4gSSE9PS0xJiZJPT09dH0sVHQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKFAoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIXBlKGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxLdD0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmVEEoVWludDhBcnJheSkpLHh0PShBLGUpPT57bGV0IEk9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxyO2Zvcig7KHI9SS5uZXh0KCkpJiYhci5kb25lOyl7bGV0IGk9ci52YWx1ZTtlLmNhbGwoQSxpWzBdLGlbMV0pfX0sUHQ9KEEsZSk9PntsZXQgdCxJPVtdO2Zvcig7KHQ9QS5leGVjKGUpKSE9PW51bGw7KUkucHVzaCh0KTtyZXR1cm4gSX0sV3Q9VSgiSFRNTEZvcm1FbGVtZW50IiksanQ9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24odCxJLHIpe3JldHVybiBJLnRvVXBwZXJDYXNlKCkrcn0pLERlPSgoe2hhc093blByb3BlcnR5OkF9KT0+KGUsdCk9PkEuY2FsbChlLHQpKShPYmplY3QucHJvdG90eXBlKSxadD1VKCJSZWdFeHAiKSxSZT0oQSxlKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLEk9e307JCh0LChyLGkpPT57ZShyLGksQSkhPT0hMSYmKElbaV09cil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLEkpfSxfdD1BPT57UmUoQSwoZSx0KT0+e2lmKFIoQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCBJPUFbdF07aWYoUihJKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kIFwnIit0KyJcJyIpfSl9fSl9LFZ0PShBLGUpPT57bGV0IHQ9e30sST1yPT57ci5mb3JFYWNoKGk9Pnt0W2ldPSEwfSl9O3JldHVybiBQKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LHp0PSgpPT57fSxYdD0oQSxlKT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6ZSksWUE9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iix5ZT0iMDEyMzQ1Njc4OSIsR2U9e0RJR0lUOnllLEFMUEhBOllBLEFMUEhBX0RJR0lUOllBK1lBLnRvVXBwZXJDYXNlKCkreWV9LHZ0PShBPTE2LGU9R2UuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpJfT1lO2Zvcig7QS0tOyl0Kz1lW01hdGgucmFuZG9tKCkqSXwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gJHQoQSl7cmV0dXJuISEoQSYmUihBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIEFJPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZih1QShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1QKEkpP1tdOnt9O3JldHVybiAkKEksKGcsbik9PntsZXQgRT10KGcscisxKTshdihFKSYmKGlbbl09RSl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sZUk9VSgiQXN5bmNGdW5jdGlvbiIpLHRJPUE9PkEmJih1QShBKXx8UihBKSkmJlIoQS50aGVuKSYmUihBLmNhdGNoKSxzPXtpc0FycmF5OlAsaXNBcnJheUJ1ZmZlcjp3ZSxpc0J1ZmZlcjp3dCxpc0Zvcm1EYXRhOkx0LGlzQXJyYXlCdWZmZXJWaWV3OnB0LGlzU3RyaW5nOkZ0LGlzTnVtYmVyOnBlLGlzQm9vbGVhbjpTdCxpc09iamVjdDp1QSxpc1BsYWluT2JqZWN0OmNBLGlzVW5kZWZpbmVkOnYsaXNEYXRlOk50LGlzRmlsZTpSdCxpc0Jsb2I6R3QsaXNSZWdFeHA6WnQsaXNGdW5jdGlvbjpSLGlzU3RyZWFtOmt0LGlzVVJMU2VhcmNoUGFyYW1zOk90LGlzVHlwZWRBcnJheTpLdCxpc0ZpbGVMaXN0OlV0LGZvckVhY2g6JCxtZXJnZTpxQSxleHRlbmQ6TXQsdHJpbTpKdCxzdHJpcEJPTTpidCxpbmhlcml0czpIdCx0b0ZsYXRPYmplY3Q6WXQsa2luZE9mOmZBLGtpbmRPZlRlc3Q6VSxlbmRzV2l0aDpxdCx0b0FycmF5OlR0LGZvckVhY2hFbnRyeTp4dCxtYXRjaEFsbDpQdCxpc0hUTUxGb3JtOld0LGhhc093blByb3BlcnR5OkRlLGhhc093blByb3A6RGUscmVkdWNlRGVzY3JpcHRvcnM6UmUsZnJlZXplTWV0aG9kczpfdCx0b09iamVjdFNldDpWdCx0b0NhbWVsQ2FzZTpqdCxub29wOnp0LHRvRmluaXRlTnVtYmVyOlh0LGZpbmRLZXk6RmUsZ2xvYmFsOlNlLGlzQ29udGV4dERlZmluZWQ6TmUsQUxQSEFCRVQ6R2UsZ2VuZXJhdGVTdHJpbmc6dnQsaXNTcGVjQ29tcGxpYW50Rm9ybTokdCx0b0pTT05PYmplY3Q6QUksaXNBc3luY0ZuOmVJLGlzVGhlbmFibGU6dEl9O2Z1bmN0aW9uIFcoQSxlLHQsSSxyKXtFcnJvci5jYWxsKHRoaXMpLEVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsdGhpcy5jb25zdHJ1Y3Rvcik6dGhpcy5zdGFjaz1uZXcgRXJyb3IoKS5zdGFjayx0aGlzLm1lc3NhZ2U9QSx0aGlzLm5hbWU9IkF4aW9zRXJyb3IiLGUmJih0aGlzLmNvZGU9ZSksdCYmKHRoaXMuY29uZmlnPXQpLEkmJih0aGlzLnJlcXVlc3Q9SSksciYmKHRoaXMucmVzcG9uc2U9cil9cy5pbmhlcml0cyhXLEVycm9yLHt0b0pTT046ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6cy50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX19KTt2YXIgVWU9Vy5wcm90b3R5cGUsa2U9e307WyJFUlJfQkFEX09QVElPTl9WQUxVRSIsIkVSUl9CQURfT1BUSU9OIiwiRUNPTk5BQk9SVEVEIiwiRVRJTUVET1VUIiwiRVJSX05FVFdPUksiLCJFUlJfRlJfVE9PX01BTllfUkVESVJFQ1RTIiwiRVJSX0RFUFJFQ0FURUQiLCJFUlJfQkFEX1JFU1BPTlNFIiwiRVJSX0JBRF9SRVFVRVNUIiwiRVJSX0NBTkNFTEVEIiwiRVJSX05PVF9TVVBQT1JUIiwiRVJSX0lOVkFMSURfVVJMIl0uZm9yRWFjaChBPT57a2VbQV09e3ZhbHVlOkF9fSk7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVyxrZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KFVlLCJpc0F4aW9zRXJyb3IiLHt2YWx1ZTohMH0pO1cuZnJvbT0oQSxlLHQsSSxyLGkpPT57bGV0IGc9T2JqZWN0LmNyZWF0ZShVZSk7cmV0dXJuIHMudG9GbGF0T2JqZWN0KEEsZyxmdW5jdGlvbihFKXtyZXR1cm4gRSE9PUVycm9yLnByb3RvdHlwZX0sbj0+biE9PSJpc0F4aW9zRXJyb3IiKSxXLmNhbGwoZyxBLm1lc3NhZ2UsZSx0LEksciksZy5jYXVzZT1BLGcubmFtZT1BLm5hbWUsaSYmT2JqZWN0LmFzc2lnbihnLGkpLGd9O3ZhciBsPVc7dmFyIGhBPW51bGw7ZnVuY3Rpb24gS0EoQSl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChBKXx8cy5pc0FycmF5KEEpfWZ1bmN0aW9uIE9lKEEpe3JldHVybiBzLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIExlKEEsZSx0KXtyZXR1cm4gQT9BLmNvbmNhdChlKS5tYXAoZnVuY3Rpb24ocixpKXtyZXR1cm4gcj1PZShyKSwhdCYmaT8iWyIrcisiXSI6cn0pLmpvaW4odD8iLiI6IiIpOmV9ZnVuY3Rpb24gSUkoQSl7cmV0dXJuIHMuaXNBcnJheShBKSYmIUEuc29tZShLQSl9dmFyIHJJPXMudG9GbGF0T2JqZWN0KHMse30sbnVsbCxmdW5jdGlvbihlKXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QoZSl9KTtmdW5jdGlvbiBpSShBLGUsdCl7aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7ZT1lfHxuZXcoaEF8fEZvcm1EYXRhKSx0PXMudG9GbGF0T2JqZWN0KHQse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLG0pe3JldHVybiFzLmlzVW5kZWZpbmVkKG1bZl0pfSk7bGV0IEk9dC5tZXRhVG9rZW5zLHI9dC52aXNpdG9yfHxCLGk9dC5kb3RzLGc9dC5pbmRleGVzLEU9KHQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmcy5pc1NwZWNDb21wbGlhbnRGb3JtKGUpO2lmKCFzLmlzRnVuY3Rpb24ocikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBvKFEpe2lmKFE9PT1udWxsKXJldHVybiIiO2lmKHMuaXNEYXRlKFEpKXJldHVybiBRLnRvSVNPU3RyaW5nKCk7aWYoIUUmJnMuaXNCbG9iKFEpKXRocm93IG5ldyBsKCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBzLmlzQXJyYXlCdWZmZXIoUSl8fHMuaXNUeXBlZEFycmF5KFEpP0UmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtRXSk6QnVmZmVyLmZyb20oUSk6UX1mdW5jdGlvbiBCKFEsZixtKXtsZXQgdz1RO2lmKFEmJiFtJiZ0eXBlb2YgUT09Im9iamVjdCIpe2lmKHMuZW5kc1dpdGgoZiwie30iKSlmPUk/ZjpmLnNsaWNlKDAsLTIpLFE9SlNPTi5zdHJpbmdpZnkoUSk7ZWxzZSBpZihzLmlzQXJyYXkoUSkmJklJKFEpfHwocy5pc0ZpbGVMaXN0KFEpfHxzLmVuZHNXaXRoKGYsIltdIikpJiYodz1zLnRvQXJyYXkoUSkpKXJldHVybiBmPU9lKGYpLHcuZm9yRWFjaChmdW5jdGlvbihLLEpBKXshKHMuaXNVbmRlZmluZWQoSyl8fEs9PT1udWxsKSYmZS5hcHBlbmQoZz09PSEwP0xlKFtmXSxKQSxpKTpnPT09bnVsbD9mOmYrIltdIixvKEspKX0pLCExfXJldHVybiBLQShRKT8hMDooZS5hcHBlbmQoTGUobSxmLGkpLG8oUSkpLCExKX1sZXQgYz1bXSxhPU9iamVjdC5hc3NpZ24ockkse2RlZmF1bHRWaXNpdG9yOkIsY29udmVydFZhbHVlOm8saXNWaXNpdGFibGU6S0F9KTtmdW5jdGlvbiBDKFEsZil7aWYoIXMuaXNVbmRlZmluZWQoUSkpe2lmKGMuaW5kZXhPZihRKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Yy5wdXNoKFEpLHMuZm9yRWFjaChRLGZ1bmN0aW9uKHcsTyl7KCEocy5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZyLmNhbGwoZSx3LHMuaXNTdHJpbmcoTyk/Ty50cmltKCk6TyxmLGEpKT09PSEwJiZDKHcsZj9mLmNvbmNhdChPKTpbT10pfSksYy5wb3AoKX19aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBDKEEpLGV9dmFyIEo9aUk7ZnVuY3Rpb24gSmUoQSl7bGV0IGU9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIiwiJTI1MDAiOiJcXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shXCcoKX5dfCUyNTIwfCUyNTAwL2csZnVuY3Rpb24oSSl7cmV0dXJuIGVbSV19KX1mdW5jdGlvbiBNZShBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJkooQSx0aGlzLGUpfXZhciBiZT1NZS5wcm90b3R5cGU7YmUuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O2JlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24oSSl7cmV0dXJuIGUuY2FsbCh0aGlzLEksSmUpfTpKZTtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiB0KHJbMF0pKyI9Iit0KHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgZEE9TWU7ZnVuY3Rpb24gZ0koQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lMjUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNTI0L2csIiQiKS5yZXBsYWNlKC8lMjUyQy9naSwiLCIpLnJlcGxhY2UoLyUyNTIwL2csIisiKS5yZXBsYWNlKC8lMjU1Qi9naSwiWyIpLnJlcGxhY2UoLyUyNTVEL2dpLCJdIil9ZnVuY3Rpb24gQUEoQSxlLHQpe2lmKCFlKXJldHVybiBBO2xldCBJPXQmJnQuZW5jb2RlfHxnSSxyPXQmJnQuc2VyaWFsaXplLGk7aWYocj9pPXIoZSx0KTppPXMuaXNVUkxTZWFyY2hQYXJhbXMoZSk/ZS50b1N0cmluZygpOm5ldyBkQShlLHQpLnRvU3RyaW5nKEkpLGkpe2xldCBnPUEuaW5kZXhPZigiJTIzIik7ZyE9PS0xJiYoQT1BLnNsaWNlKDAsZykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIHhBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LEkpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6ST9JLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ST9JLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihJKXtJIT09bnVsbCYmZShJKX0pfX0sUEE9eEE7dmFyIG1BPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgSGU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOmRBO3ZhciBZZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIHFlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIG9JPSgoKT0+e2xldCBBO3JldHVybiB0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmKChBPW5hdmlnYXRvci5wcm9kdWN0KT09PSJSZWFjdE5hdGl2ZSJ8fEE9PT0iTmF0aXZlU2NyaXB0Inx8QT09PSJOUyIpPyExOnR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUifSkoKSxuST0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKSxEPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkhlLEZvcm1EYXRhOlllLEJsb2I6cWV9LGlzU3RhbmRhcmRCcm93c2VyRW52Om9JLGlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52Om5JLHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTtmdW5jdGlvbiBXQShBLGUpe3JldHVybiBKKEEsbmV3IEQuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LEkscixpKXtyZXR1cm4gRC5pc05vZGUmJnMuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKEksdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LGUpKX1mdW5jdGlvbiBhSShBKXtyZXR1cm4gcy5tYXRjaEFsbCgvXFx3K3xcXFsoXFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIHNJKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSksSSxyPXQubGVuZ3RoLGk7Zm9yKEk9MDtJPHI7SSsrKWk9dFtJXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gQ0koQSl7ZnVuY3Rpb24gZSh0LEkscixpKXtsZXQgZz10W2krK10sbj1OdW1iZXIuaXNGaW5pdGUoK2cpLEU9aT49dC5sZW5ndGg7cmV0dXJuIGc9IWcmJnMuaXNBcnJheShyKT9yLmxlbmd0aDpnLEU/KHMuaGFzT3duUHJvcChyLGcpP3JbZ109W3JbZ10sSV06cltnXT1JLCFuKTooKCFyW2ddfHwhcy5pc09iamVjdChyW2ddKSkmJihyW2ddPVtdKSxlKHQsSSxyW2ddLGkpJiZzLmlzQXJyYXkocltnXSkmJihyW2ddPXNJKHJbZ10pKSwhbil9aWYocy5pc0Zvcm1EYXRhKEEpJiZzLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIHMuZm9yRWFjaEVudHJ5KEEsKEkscik9PntlKGFJKEkpLHIsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIERBPUNJO3ZhciBCST17IkNvbnRlbnQtVHlwZSI6dm9pZCAwfTtmdW5jdGlvbiBRSShBLGUsdCl7aWYocy5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKGV8fEpTT04ucGFyc2UpKEEpLHMudHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgeUE9e3RyYW5zaXRpb25hbDptQSxhZGFwdGVyOlsieGhyIiwiaHR0cCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7bGV0IEk9dC5nZXRDb250ZW50VHlwZSgpfHwiIixyPUkuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLGk9cy5pc09iamVjdChlKTtpZihpJiZzLmlzSFRNTEZvcm0oZSkmJihlPW5ldyBGb3JtRGF0YShlKSkscy5pc0Zvcm1EYXRhKGUpKXJldHVybiByJiZyP0pTT04uc3RyaW5naWZ5KERBKGUpKTplO2lmKHMuaXNBcnJheUJ1ZmZlcihlKXx8cy5pc0J1ZmZlcihlKXx8cy5pc1N0cmVhbShlKXx8cy5pc0ZpbGUoZSl8fHMuaXNCbG9iKGUpKXJldHVybiBlO2lmKHMuaXNBcnJheUJ1ZmZlclZpZXcoZSkpcmV0dXJuIGUuYnVmZmVyO2lmKHMuaXNVUkxTZWFyY2hQYXJhbXMoZSkpcmV0dXJuIHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksZS50b1N0cmluZygpO2xldCBuO2lmKGkpe2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIFdBKGUsdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigobj1zLmlzRmlsZUxpc3QoZSkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEU9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBKKG4/eyJmaWxlc1tdIjplfTplLEUmJm5ldyBFLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gaXx8cj8odC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLFFJKGUpKTplfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKGUpe2xldCB0PXRoaXMudHJhbnNpdGlvbmFsfHx5QS50cmFuc2l0aW9uYWwsST10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLHI9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYoZSYmcy5pc1N0cmluZyhlKSYmKEkmJiF0aGlzLnJlc3BvbnNlVHlwZXx8cikpe2xldCBnPSEodCYmdC5zaWxlbnRKU09OUGFyc2luZykmJnI7dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpfWNhdGNoKG4pe2lmKGcpdGhyb3cgbi5uYW1lPT09IlN5bnRheEVycm9yIj9sLmZyb20obixsLkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOm59fXJldHVybiBlfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpELmNsYXNzZXMuRm9ybURhdGEsQmxvYjpELmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTIwMCYmZTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoifX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiXSxmdW5jdGlvbihlKXt5QS5oZWFkZXJzW2VdPXt9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7eUEuaGVhZGVyc1tlXT1zLm1lcmdlKEJJKX0pO3ZhciBqPXlBO3ZhciBFST1zLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLFRlPUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgJTBBYCkuZm9yRWFjaChmdW5jdGlvbihnKXtyPWcuaW5kZXhPZigiOiIpLHQ9Zy5zdWJzdHJpbmcoMCxyKS50cmltKCkudG9Mb3dlckNhc2UoKSxJPWcuc3Vic3RyaW5nKHIrMSkudHJpbSgpLCEoIXR8fGVbdF0mJkVJW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2goSSk6ZVt0XT1bSV06ZVt0XT1lW3RdP2VbdF0rIiwgIitJOkkpfSksZX07dmFyIEtlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiB3QShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6cy5pc0FycmF5KEEpP0EubWFwKHdBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gY0koQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15cXHMsOz1dKylcXHMqKD86PVxccyooW14sO10rKSk/L2csSTtmb3IoO0k9dC5leGVjKEEpOyllW0lbMV1dPUlbMl07cmV0dXJuIGV9dmFyIGZJPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhJTIzJCUmXCcqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIGpBKEEsZSx0LEkscil7aWYocy5pc0Z1bmN0aW9uKEkpKXJldHVybiBJLmNhbGwodGhpcyxlLHQpO2lmKHImJihlPXQpLCEhcy5pc1N0cmluZyhlKSl7aWYocy5pc1N0cmluZyhJKSlyZXR1cm4gZS5pbmRleE9mKEkpIT09LTE7aWYocy5pc1JlZ0V4cChJKSlyZXR1cm4gSS50ZXN0KGUpfX1mdW5jdGlvbiBsSShBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxcZF0pKFxcdyopL2csKGUsdCxJKT0+dC50b1VwcGVyQ2FzZSgpK0kpfWZ1bmN0aW9uIHVJKEEsZSl7bGV0IHQ9cy50b0NhbWVsQ2FzZSgiICIrZSk7WyJnZXQiLCJzZXQiLCJoYXMiXS5mb3JFYWNoKEk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxJK3Qse3ZhbHVlOmZ1bmN0aW9uKHIsaSxnKXtyZXR1cm4gdGhpc1tJXS5jYWxsKHRoaXMsZSxyLGksZyl9LGNvbmZpZ3VyYWJsZTohMH0pfSl9dmFyIFo9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkobixFLG8pe2xldCBCPWVBKEUpO2lmKCFCKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgYz1zLmZpbmRLZXkocixCKTsoIWN8fHJbY109PT12b2lkIDB8fG89PT0hMHx8bz09PXZvaWQgMCYmcltjXSE9PSExKSYmKHJbY3x8RV09d0EobikpfWxldCBnPShuLEUpPT5zLmZvckVhY2gobiwobyxCKT0+aShvLEIsRSkpO3JldHVybiBzLmlzUGxhaW5PYmplY3QoZSl8fGUgaW5zdGFuY2VvZiB0aGlzLmNvbnN0cnVjdG9yP2coZSx0KTpzLmlzU3RyaW5nKGUpJiYoZT1lLnRyaW0oKSkmJiFmSShlKT9nKFRlKGUpLHQpOmUhPW51bGwmJmkodCxlLEkpLHRoaXN9Z2V0KGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gY0kocik7aWYocy5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKHMuaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGpBKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkoZyl7aWYoZz1lQShnKSxnKXtsZXQgbj1zLmZpbmRLZXkoSSxnKTtuJiYoIXR8fGpBKEksSVtuXSxuLHQpKSYmKGRlbGV0ZSBJW25dLHI9ITApfX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGpBKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IGc9cy5maW5kS2V5KEksaSk7aWYoZyl7dFtnXT13QShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IG49ZT9sSShpKTpTdHJpbmcoaSkudHJpbSgpO24hPT1pJiZkZWxldGUgdFtpXSx0W25dPXdBKHIpLElbbl09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gcy5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJnMuaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYCUwQWApfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0aGlzP2U6bmV3IHRoaXMoZSl9c3RhdGljIGNvbmNhdChlLC4uLnQpe2xldCBJPW5ldyB0aGlzKGUpO3JldHVybiB0LmZvckVhY2gocj0+SS5zZXQocikpLEl9c3RhdGljIGFjY2Vzc29yKGUpe2xldCBJPSh0aGlzW0tlXT10aGlzW0tlXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLHI9dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gaShnKXtsZXQgbj1lQShnKTtJW25dfHwodUkocixnKSxJW25dPSEwKX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHRoaXN9fTtaLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtzLmZyZWV6ZU1ldGhvZHMoWi5wcm90b3R5cGUpO3MuZnJlZXplTWV0aG9kcyhaKTt2YXIgcD1aO2Z1bmN0aW9uIHRBKEEsZSl7bGV0IHQ9dGhpc3x8aixJPWV8fHQscj1wLmZyb20oSS5oZWFkZXJzKSxpPUkuZGF0YTtyZXR1cm4gcy5mb3JFYWNoKEEsZnVuY3Rpb24obil7aT1uLmNhbGwodCxpLHIubm9ybWFsaXplKCksZT9lLnN0YXR1czp2b2lkIDApfSksci5ub3JtYWxpemUoKSxpfWZ1bmN0aW9uIElBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9ZnVuY3Rpb24geGUoQSxlLHQpe2wuY2FsbCh0aGlzLEE/PyJjYW5jZWxlZCIsbC5FUlJfQ0FOQ0VMRUQsZSx0KSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IifXMuaW5oZXJpdHMoeGUsbCx7X19DQU5DRUxfXzohMH0pO3ZhciBNPXhlO2Z1bmN0aW9uIFpBKEEsZSx0KXtsZXQgST10LmNvbmZpZy52YWxpZGF0ZVN0YXR1czshdC5zdGF0dXN8fCFJfHxJKHQuc3RhdHVzKT9BKHQpOmUobmV3IGwoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIit0LnN0YXR1cyxbbC5FUlJfQkFEX1JFUVVFU1QsbC5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKHQuc3RhdHVzLzEwMCktNF0sdC5jb25maWcsdC5yZXF1ZXN0LHQpKX12YXIgUGU9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LEkscixpLGcsbil7bGV0IEU9W107RS5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChJKSkscy5pc051bWJlcihyKSYmRS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUocikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmRS5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhnKSYmRS5wdXNoKCJkb21haW49IitnKSxuPT09ITAmJkUucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPUUuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgST1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xcXFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIEk/ZGVjb2RlVVJJQ29tcG9uZW50KElbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBfQShBKXtyZXR1cm4vXihbYS16XVthLXpcXGQrXFwtLl0qOik/XFwvXFwvL2kudGVzdChBKX1mdW5jdGlvbiBWQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXFwvKyQvLCIiKSsiLyIrZS5yZXBsYWNlKC9eXFwvKy8sIiIpOkF9ZnVuY3Rpb24gckEoQSxlKXtyZXR1cm4gQSYmIV9BKGUpP1ZBKEEsZSk6ZX12YXIgV2U9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBlPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIiksSTtmdW5jdGlvbiByKGkpe2xldCBnPWk7cmV0dXJuIGUmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsZyksZz10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixnKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiUyMy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIEk9cih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oZyl7bGV0IG49cy5pc1N0cmluZyhnKT9yKGcpOmc7cmV0dXJuIG4ucHJvdG9jb2w9PT1JLnByb3RvY29sJiZuLmhvc3Q9PT1JLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIHpBKEEpe2xldCBlPS9eKFstK1xcd117MSwyNX0pKDo/XFwvXFwvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBoSShBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsZztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKEUpe2xldCBvPURhdGUubm93KCksQj1JW2ldO2d8fChnPW8pLHRbcl09RSxJW3JdPW87bGV0IGM9aSxhPTA7Zm9yKDtjIT09cjspYSs9dFtjKytdLGM9YyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksby1nPGUpcmV0dXJuO2xldCBDPUImJm8tQjtyZXR1cm4gQz9NYXRoLnJvdW5kKGEqMWUzL0MpOnZvaWQgMH19dmFyIGplPWhJO2Z1bmN0aW9uIFplKEEsZSl7bGV0IHQ9MCxJPWplKDUwLDI1MCk7cmV0dXJuIHI9PntsZXQgaT1yLmxvYWRlZCxnPXIubGVuZ3RoQ29tcHV0YWJsZT9yLnRvdGFsOnZvaWQgMCxuPWktdCxFPUkobiksbz1pPD1nO3Q9aTtsZXQgQj17bG9hZGVkOmksdG90YWw6Zyxwcm9ncmVzczpnP2kvZzp2b2lkIDAsYnl0ZXM6bixyYXRlOkV8fHZvaWQgMCxlc3RpbWF0ZWQ6RSYmZyYmbz8oZy1pKS9FOnZvaWQgMCxldmVudDpyfTtCW2U/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsQShCKX19dmFyIGRJPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsX2U9ZEkmJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LEkpe2xldCByPUEuZGF0YSxpPXAuZnJvbShBLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGc9QS5yZXNwb25zZVR5cGUsbjtmdW5jdGlvbiBFKCl7QS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShuKSxBLnNpZ25hbCYmQS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG4pfXMuaXNGb3JtRGF0YShyKSYmKEQuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEQuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/aS5zZXRDb250ZW50VHlwZSghMSk6aS5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YTsiLCExKSk7bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IEM9QS5hdXRoLnVzZXJuYW1lfHwiIixRPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoQysiOiIrUSkpfWxldCBCPXJBKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksQUEoQixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIGMoKXtpZighbylyZXR1cm47bGV0IEM9cC5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksZj17ZGF0YTohZ3x8Zz09PSJ0ZXh0Inx8Zz09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOkMsY29uZmlnOkEscmVxdWVzdDpvfTtaQShmdW5jdGlvbih3KXt0KHcpLEUoKX0sZnVuY3Rpb24odyl7SSh3KSxFKCl9LGYpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9YzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoYyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihJKG5ldyBsKCJSZXF1ZXN0IGFib3J0ZWQiLGwuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe0kobmV3IGwoIk5ldHdvcmsgRXJyb3IiLGwuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBRPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixmPUEudHJhbnNpdGlvbmFsfHxtQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihRPUEudGltZW91dEVycm9yTWVzc2FnZSksSShuZXcgbChRLGYuY2xhcmlmeVRpbWVvdXRFcnJvcj9sLkVUSU1FRE9VVDpsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LEQuaXNTdGFuZGFyZEJyb3dzZXJFbnYpe2xldCBDPShBLndpdGhDcmVkZW50aWFsc3x8V2UoQikpJiZBLnhzcmZDb29raWVOYW1lJiZQZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO0MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsQyl9cj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBvJiZzLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihRLGYpe28uc2V0UmVxdWVzdEhlYWRlcihmLFEpfSkscy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChvLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxnJiZnIT09Impzb24iJiYoby5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLnVwbG9hZCYmby51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihuPUM9PntvJiYoSSghQ3x8Qy50eXBlP25ldyBNKG51bGwsQSxvKTpDKSxvLmFib3J0KCksbz1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobiksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP24oKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbikpKTtsZXQgYT16QShCKTtpZihhJiZELnByb3RvY29scy5pbmRleE9mKGEpPT09LTEpe0kobmV3IGwoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrYSsiOiIsbC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1vLnNlbmQocnx8bnVsbCl9KX07dmFyIHBBPXtodHRwOmhBLHhocjpfZX07cy5mb3JFYWNoKHBBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyIFZlPXtnZXRBZGFwdGVyOkE9PntBPXMuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsdCxJO2ZvcihsZXQgcj0wO3I8ZSYmKHQ9QVtyXSwhKEk9cy5pc1N0cmluZyh0KT9wQVt0LnRvTG93ZXJDYXNlKCldOnQpKTtyKyspO2lmKCFJKXRocm93IEk9PT0hMT9uZXcgbChgQWRhcHRlciAke3R9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50YCwiRVJSX05PVF9TVVBQT1JUIik6bmV3IEVycm9yKHMuaGFzT3duUHJvcChwQSx0KT9gQWRhcHRlciBcJyR7dH1cJyBpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZGA6YFVua25vd24gYWRhcHRlciBcJyR7dH1cJ2ApO2lmKCFzLmlzRnVuY3Rpb24oSSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiYWRhcHRlciBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBJfSxhZGFwdGVyczpwQX07ZnVuY3Rpb24gWEEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IE0obnVsbCxBKX1mdW5jdGlvbiBGQShBKXtyZXR1cm4gWEEoQSksQS5oZWFkZXJzPXAuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksVmUuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fGouYWRhcHRlcikoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gWEEoQSksSS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1wLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gSUEoSSl8fChYQShBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1wLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIHplPUE9PkEgaW5zdGFuY2VvZiBwP0EudG9KU09OKCk6QTtmdW5jdGlvbiBrKEEsZSl7ZT1lfHx7fTtsZXQgdD17fTtmdW5jdGlvbiBJKG8sQixjKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KG8pJiZzLmlzUGxhaW5PYmplY3QoQik/cy5tZXJnZS5jYWxsKHtjYXNlbGVzczpjfSxvLEIpOnMuaXNQbGFpbk9iamVjdChCKT9zLm1lcmdlKHt9LEIpOnMuaXNBcnJheShCKT9CLnNsaWNlKCk6Qn1mdW5jdGlvbiByKG8sQixjKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyxjKX1lbHNlIHJldHVybiBJKG8sQixjKX1mdW5jdGlvbiBpKG8sQil7aWYoIXMuaXNVbmRlZmluZWQoQikpcmV0dXJuIEkodm9pZCAwLEIpfWZ1bmN0aW9uIGcobyxCKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyl9ZWxzZSByZXR1cm4gSSh2b2lkIDAsQil9ZnVuY3Rpb24gbihvLEIsYyl7aWYoYyBpbiBlKXJldHVybiBJKG8sQik7aWYoYyBpbiBBKXJldHVybiBJKHZvaWQgMCxvKX1sZXQgRT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsYWRhcHRlcjpnLHJlc3BvbnNlVHlwZTpnLHhzcmZDb29raWVOYW1lOmcseHNyZkhlYWRlck5hbWU6ZyxvblVwbG9hZFByb2dyZXNzOmcsb25Eb3dubG9hZFByb2dyZXNzOmcsZGVjb21wcmVzczpnLG1heENvbnRlbnRMZW5ndGg6ZyxtYXhCb2R5TGVuZ3RoOmcsYmVmb3JlUmVkaXJlY3Q6Zyx0cmFuc3BvcnQ6ZyxodHRwQWdlbnQ6ZyxodHRwc0FnZW50OmcsY2FuY2VsVG9rZW46Zyxzb2NrZXRQYXRoOmcscmVzcG9uc2VFbmNvZGluZzpnLHZhbGlkYXRlU3RhdHVzOm4saGVhZGVyczoobyxCKT0+cih6ZShvKSx6ZShCKSwhMCl9O3JldHVybiBzLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihCKXtsZXQgYz1FW0JdfHxyLGE9YyhBW0JdLGVbQl0sQik7cy5pc1VuZGVmaW5lZChhKSYmYyE9PW58fCh0W0JdPWEpfSksdH12YXIgU0E9IjEuNC4wIjt2YXIgdkE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57dkFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIFhlPXt9O3ZBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQsSSl7ZnVuY3Rpb24gcihpLGcpe3JldHVybiJbQXhpb3MgdiIrU0ErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIraSsiXCciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4oaSxnLG4pPT57aWYoZT09PSExKXRocm93IG5ldyBsKHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksbC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFYZVtnXSYmKFhlW2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKGksZyxuKTohMH19O2Z1bmN0aW9uIG1JKEEsZSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGwoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgaT1JW3JdLGc9ZVtpXTtpZihnKXtsZXQgbj1BW2ldLEU9bj09PXZvaWQgMHx8ZyhuLGksQSk7aWYoRSE9PSEwKXRocm93IG5ldyBsKCJvcHRpb24gIitpKyIgbXVzdCBiZSAiK0UsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyBsKCJVbmtub3duIG9wdGlvbiAiK2ksbC5FUlJfQkFEX09QVElPTil9fXZhciBOQT17YXNzZXJ0T3B0aW9uczptSSx2YWxpZGF0b3JzOnZBfTt2YXIgYj1OQS52YWxpZGF0b3JzLF89Y2xhc3N7Y29uc3RydWN0b3IoZSl7dGhpcy5kZWZhdWx0cz1lLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBQQSxyZXNwb25zZTpuZXcgUEF9fXJlcXVlc3QoZSx0KXt0eXBlb2YgZT09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9ZSk6dD1lfHx7fSx0PWsodGhpcy5kZWZhdWx0cyx0KTtsZXR7dHJhbnNpdGlvbmFsOkkscGFyYW1zU2VyaWFsaXplcjpyLGhlYWRlcnM6aX09dDtJIT09dm9pZCAwJiZOQS5hc3NlcnRPcHRpb25zKEkse3NpbGVudEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Yi50cmFuc2l0aW9uYWwoYi5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbil9LCExKSxyIT1udWxsJiYocy5pc0Z1bmN0aW9uKHIpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9Ok5BLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOmIuZnVuY3Rpb24sc2VyaWFsaXplOmIuZnVuY3Rpb259LCEwKSksdC5tZXRob2Q9KHQubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGc7Zz1pJiZzLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKSxnJiZzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBpW1FdfSksdC5oZWFkZXJzPXAuY29uY2F0KGcsaSk7bGV0IG49W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7dHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITF8fChFPUUmJmYuc3luY2hyb25vdXMsbi51bnNoaWZ0KGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpKX0pO2xldCBvPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZil7by5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IEIsYz0wLGE7aWYoIUUpe2xldCBRPVtGQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKFEudW5zaGlmdC5hcHBseShRLG4pLFEucHVzaC5hcHBseShRLG8pLGE9US5sZW5ndGgsQj1Qcm9taXNlLnJlc29sdmUodCk7YzxhOylCPUIudGhlbihRW2MrK10sUVtjKytdKTtyZXR1cm4gQn1hPW4ubGVuZ3RoO2xldCBDPXQ7Zm9yKGM9MDtjPGE7KXtsZXQgUT1uW2MrK10sZj1uW2MrK107dHJ5e0M9UShDKX1jYXRjaChtKXtmLmNhbGwodGhpcyxtKTticmVha319dHJ5e0I9RkEuY2FsbCh0aGlzLEMpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3IoYz0wLGE9by5sZW5ndGg7YzxhOylCPUIudGhlbihvW2MrK10sb1tjKytdKTtyZXR1cm4gQn1nZXRVcmkoZSl7ZT1rKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9ckEoZS5iYXNlVVJMLGUudXJsKTtyZXR1cm4gQUEodCxlLnBhcmFtcyxlLnBhcmFtc1NlcmlhbGl6ZXIpfX07cy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihlKXtfLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LEkpe3JldHVybiB0aGlzLnJlcXVlc3QoayhJfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChJKXtyZXR1cm4gZnVuY3Rpb24oaSxnLG4pe3JldHVybiB0aGlzLnJlcXVlc3QoayhufHx7fSx7bWV0aG9kOmUsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDppLGRhdGE6Z30pKX19Xy5wcm90b3R5cGVbZV09dCgpLF8ucHJvdG90eXBlW2UrIkZvcm0iXT10KCEwKX0pO3ZhciBpQT1fO3ZhciAkQT1jbGFzcyBBe2NvbnN0cnVjdG9yKGUpe2lmKHR5cGVvZiBlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dD1pfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IGk9SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2ktLSA+MDspSS5fbGlzdGVuZXJzW2ldKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBpLGc9bmV3IFByb21pc2Uobj0+e0kuc3Vic2NyaWJlKG4pLGk9bn0pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShpKX0sZ30sZShmdW5jdGlvbihpLGcsbil7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgTShpLGcsbiksdChJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfXVuc3Vic2NyaWJlKGUpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKGUpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgZTtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24ocil7ZT1yfSksY2FuY2VsOmV9fX0sdmU9JEE7ZnVuY3Rpb24gQWUoQSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBBLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGVlKEEpe3JldHVybiBzLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciB0ZT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXModGUpLmZvckVhY2goKFtBLGVdKT0+e3RlW2VdPUF9KTt2YXIgJGU9dGU7ZnVuY3Rpb24gQXQoQSl7bGV0IGU9bmV3IGlBKEEpLHQ9WChpQS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gcy5leHRlbmQodCxpQS5wcm90b3R5cGUsZSx7YWxsT3duS2V5czohMH0pLHMuZXh0ZW5kKHQsZSxudWxsLHthbGxPd25LZXlzOiEwfSksdC5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIEF0KGsoQSxyKSl9LHR9dmFyIGg9QXQoaik7aC5BeGlvcz1pQTtoLkNhbmNlbGVkRXJyb3I9TTtoLkNhbmNlbFRva2VuPXZlO2guaXNDYW5jZWw9SUE7aC5WRVJTSU9OPVNBO2gudG9Gb3JtRGF0YT1KO2guQXhpb3NFcnJvcj1sO2guQ2FuY2VsPWguQ2FuY2VsZWRFcnJvcjtoLmFsbD1mdW5jdGlvbihlKXtyZXR1cm4gUHJvbWlzZS5hbGwoZSl9O2guc3ByZWFkPUFlO2guaXNBeGlvc0Vycm9yPWVlO2gubWVyZ2VDb25maWc9aztoLkF4aW9zSGVhZGVycz1wO2guZm9ybVRvSlNPTj1BPT5EQShzLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO2guSHR0cFN0YXR1c0NvZGU9JGU7aC5kZWZhdWx0PWg7dmFyIFJBPWg7dmFye0F4aW9zOlNnLEF4aW9zRXJyb3I6TmcsQ2FuY2VsZWRFcnJvcjpSZyxpc0NhbmNlbDpHZyxDYW5jZWxUb2tlbjpVZyxWRVJTSU9OOmtnLGFsbDpMZyxDYW5jZWw6T2csaXNBeGlvc0Vycm9yOkpnLHNwcmVhZDpNZyx0b0Zvcm1EYXRhOmJnLEF4aW9zSGVhZGVyczpIZyxIdHRwU3RhdHVzQ29kZTpZZyxmb3JtVG9KU09OOnFnLG1lcmdlQ29uZmlnOlRnfT1SQTt2YXIgZ0EsTCxyZSxJZT17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe3JlPW5ldyBVaW50OEFycmF5KEwuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSxHQT1jbGFzc3tpbml0KCl7cmV0dXJuIGdBfHwodHlwZW9mIGZldGNoPCJ1Ij9nQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK2V0KS50aGVuKGU9PmUuYXJyYXlCdWZmZXIoKSkudGhlbihlPT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShlLEllKSkudGhlbih0aGlzLl9pbml0KTpnQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbShldCwiYmFzZTY0IiksSWUpLnRoZW4odGhpcy5faW5pdCksZ0EpfV9pbml0KGUpe0w9ZS5pbnN0YW5jZSxJZS5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUoZSx0PTApe2lmKCFMKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBJPWUuYnl0ZUxlbmd0aCxyPUwuZXhwb3J0cy5tYWxsb2MoSSk7cmUuc2V0KGUsciksdD10fHxOdW1iZXIoTC5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUocixJKSk7bGV0IGk9TC5leHBvcnRzLm1hbGxvYyh0KSxnPUwuZXhwb3J0cy5aU1REX2RlY29tcHJlc3MoaSx0LHIsSSksbj1yZS5zbGljZShpLGkrZyk7cmV0dXJuIEwuZXhwb3J0cy5mcmVlKHIpLEwuZXhwb3J0cy5mcmVlKGkpLG59fSxldD0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciB0dD1uZXcgR0EsSXQ9ITE7YXN5bmMgZnVuY3Rpb24gREkoQSxlKXtsZXQgdD1udWxsO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IEk9YCR7dH0ud2FzbWAscj1hd2FpdCBSQS5nZXQoYCR7SX0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KTtJdHx8KGF3YWl0IHR0LmluaXQoKSxJdD0hMCk7bGV0IGc9dHQuZGVjb2RlKG5ldyBVaW50OEFycmF5KHIuZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6Z30pfXZhciBydD1ESTt2YXIgVUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiB5SShBLGUpe2xldCB0PUEsST1BLHI9bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYodD1uZXcgVVJMKEEuaHJlZiksST10LmhyZWYpLFVBLmhhcyhJKXx8VUEuc2V0KEksYXdhaXQgcnQodCxlKSkscj1VQS5nZXQoSSkscn12YXIgRz15STt2YXIgd0k9bmV3IE1hcChbWyJpbWFnZS9qcGVnIiwiSlBFR0ltYWdlSU8iXSxbImltYWdlL3BuZyIsIlBOR0ltYWdlSU8iXSxbImltYWdlL3RpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiaW1hZ2UveC1tcy1ibXAiLCJCTVBJbWFnZUlPIl0sWyJpbWFnZS94LWJtcCIsIkJNUEltYWdlSU8iXSxbImltYWdlL2JtcCIsIkJNUEltYWdlSU8iXSxbImFwcGxpY2F0aW9uL2RpY29tIiwiR0RDTUltYWdlSU8iXV0pLGllPXdJO3ZhciBwST1uZXcgTWFwKFtbImJtcCIsIkJNUEltYWdlSU8iXSxbIkJNUCIsIkJNUEltYWdlSU8iXSxbImRjbSIsIkdEQ01JbWFnZUlPIl0sWyJEQ00iLCJHRENNSW1hZ2VJTyJdLFsiZ2lwbCIsIkdpcGxJbWFnZUlPIl0sWyJnaXBsLmd6IiwiR2lwbEltYWdlSU8iXSxbImhkZjUiLCJIREY1SW1hZ2VJTyJdLFsianBnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRyIsIkpQRUdJbWFnZUlPIl0sWyJqcGVnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRUciLCJKUEVHSW1hZ2VJTyJdLFsiaXdpIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yLnpzdCIsIldhc21ac3RkSW1hZ2VJTyJdLFsibHNtIiwiTFNNSW1hZ2VJTyJdLFsibW5jIiwiTUlOQ0ltYWdlSU8iXSxbIk1OQyIsIk1JTkNJbWFnZUlPIl0sWyJtbmMuZ3oiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DLkdaIiwiTUlOQ0ltYWdlSU8iXSxbIm1uYzIiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DMiIsIk1JTkNJbWFnZUlPIl0sWyJtZ2giLCJNR0hJbWFnZUlPIl0sWyJtZ3oiLCJNR0hJbWFnZUlPIl0sWyJtZ2guZ3oiLCJNR0hJbWFnZUlPIl0sWyJtaGEiLCJNZXRhSW1hZ2VJTyJdLFsibWhkIiwiTWV0YUltYWdlSU8iXSxbIm1yYyIsIk1SQ0ltYWdlSU8iXSxbIm5pYSIsIk5pZnRpSW1hZ2VJTyJdLFsibmlpIiwiTmlmdGlJbWFnZUlPIl0sWyJuaWkuZ3oiLCJOaWZ0aUltYWdlSU8iXSxbImhkciIsIk5pZnRpSW1hZ2VJTyJdLFsibnJyZCIsIk5ycmRJbWFnZUlPIl0sWyJOUlJEIiwiTnJyZEltYWdlSU8iXSxbIm5oZHIiLCJOcnJkSW1hZ2VJTyJdLFsiTkhEUiIsIk5ycmRJbWFnZUlPIl0sWyJwbmciLCJQTkdJbWFnZUlPIl0sWyJQTkciLCJQTkdJbWFnZUlPIl0sWyJwaWMiLCJCaW9SYWRJbWFnZUlPIl0sWyJQSUMiLCJCaW9SYWRJbWFnZUlPIl0sWyJ0aWYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGIiwiVElGRkltYWdlSU8iXSxbInRpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGRiIsIlRJRkZJbWFnZUlPIl0sWyJ2dGsiLCJWVEtJbWFnZUlPIl0sWyJWVEsiLCJWVEtJbWFnZUlPIl0sWyJpc3EiLCJTY2FuY29JbWFnZUlPIl0sWyJJU1EiLCJTY2FuY29JbWFnZUlPIl0sWyJmZGYiLCJGREZJbWFnZUlPIl0sWyJGREYiLCJGREZJbWFnZUlPIl1dKSxnZT1wSTtmdW5jdGlvbiBGSShBKXtsZXQgZT1BLnNsaWNlKChBLmxhc3RJbmRleE9mKCIuIiktMT4+PjApKzIpO2lmKGUudG9Mb3dlckNhc2UoKT09PSJneiIpe2xldCB0PUEuc2xpY2UoMCwtMykubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoZS50b0xvd2VyQ2FzZSgpPT09ImNib3IiKXtsZXQgdD1BLnNsaWNlKDAsLTUpLmxhc3RJbmRleE9mKCIuIik7ZT1BLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKGUudG9Mb3dlckNhc2UoKT09PSJ6c3QiKXtsZXQgdD1BLnNsaWNlKDAsLTEwKS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihlLnRvTG93ZXJDYXNlKCk9PT0iemlwIil7bGV0IHQ9QS5zbGljZSgwLC00KS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9cmV0dXJuIGV9dmFyIGtBPUZJO3ZhciBTST1bIlBOR0ltYWdlSU8iLCJNZXRhSW1hZ2VJTyIsIlRJRkZJbWFnZUlPIiwiTmlmdGlJbWFnZUlPIiwiSlBFR0ltYWdlSU8iLCJOcnJkSW1hZ2VJTyIsIlZUS0ltYWdlSU8iLCJCTVBJbWFnZUlPIiwiSERGNUltYWdlSU8iLCJNSU5DSW1hZ2VJTyIsIk1SQ0ltYWdlSU8iLCJMU01JbWFnZUlPIiwiTUdISW1hZ2VJTyIsIkJpb1JhZEltYWdlSU8iLCJHaXBsSW1hZ2VJTyIsIkdFQWR3SW1hZ2VJTyIsIkdFNEltYWdlSU8iLCJHRTVJbWFnZUlPIiwiR0RDTUltYWdlSU8iLCJTY2FuY29JbWFnZUlPIiwiRkRGSW1hZ2VJTyIsIldhc21JbWFnZUlPIiwiV2FzbVpzdGRJbWFnZUlPIl0sTEE9U0k7dmFyIE5JPXtUZXh0RmlsZToiSW50ZXJmYWNlVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkludGVyZmFjZUJpbmFyeUZpbGUiLFRleHRTdHJlYW06IkludGVyZmFjZVRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiSW50ZXJmYWNlQmluYXJ5U3RyZWFtIixJbWFnZToiSW50ZXJmYWNlSW1hZ2UiLE1lc2g6IkludGVyZmFjZU1lc2giLFBvbHlEYXRhOiJJbnRlcmZhY2VQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6IkludGVyZmFjZUpzb25Db21wYXRpYmxlIn0sdT1OSTt2YXIgUkk9e1RleHQ6IlRleHQiLEJpbmFyeToiQmluYXJ5IixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2gifSxTPVJJO3ZhciBHST17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEY9R0k7dmFyIFVJPXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxUPVVJO2Z1bmN0aW9uIGtJKEEsZSl7bGV0IHQ9bnVsbDtzd2l0Y2goQSl7Y2FzZSBGLlVJbnQ4Ont0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ4Ont0PW5ldyBJbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQxNjp7dD1uZXcgVWludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDE2Ont0PW5ldyBJbnQxNkFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50MzI6e3Q9bmV3IFVpbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQzMjp7dD1uZXcgSW50MzJBcnJheShlKTticmVha31jYXNlIEYuVUludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdVaW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdVaW50NjRBcnJheShlKTp0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnSW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdJbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBULkZsb2F0MzI6e3Q9bmV3IEZsb2F0MzJBcnJheShlKTticmVha31jYXNlIFQuRmxvYXQ2NDp7dD1uZXcgRmxvYXQ2NEFycmF5KGUpO2JyZWFrfWNhc2UibnVsbCI6e3Q9bnVsbDticmVha31jYXNlIG51bGw6e3Q9bnVsbDticmVha31kZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVHlwZSBpcyBub3Qgc3VwcG9ydGVkIGFzIGEgVHlwZWRBcnJheSIpfXJldHVybiB0fXZhciBkPWtJO3ZhciBvdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixpdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoQSxlKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3BlbihlLHQuZmxhZ3MpLGk9QS5mc19zdGF0KGUpLnNpemUsZz1udWxsO290P2c9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGkpOmc9bmV3IEFycmF5QnVmZmVyKGkpO2xldCBuPW5ldyBVaW50OEFycmF5KGcpO3JldHVybiBBLmZzX3JlYWQoSSxuLDAsaSwwKSxBLmZzX2Nsb3NlKEkpLG59ZnVuY3Rpb24gbnQoQSxlLHQpe2xldCBJPW51bGw7b3Q/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ST1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksaT1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsZSx0KTtyZXR1cm4gci5zZXQoaSkscn1mdW5jdGlvbiB5KEEsZSx0LEkpe2xldCByPTA7cmV0dXJuIGUhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEksZS5idWZmZXIuYnl0ZUxlbmd0aF0pLEEuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShlLmJ1ZmZlcikscikpLHJ9ZnVuY3Rpb24gVihBLGUsdCl7bGV0IEk9SlNPTi5zdHJpbmdpZnkoZSkscj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsSS5sZW5ndGhdKTtBLndyaXRlQXNjaWlUb01lbW9yeShJLHIsITEpfWZ1bmN0aW9uIE4oQSxlLHQsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksaT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxnPW50KEEscixpKTtyZXR1cm4gZChJLGcuYnVmZmVyKX1mdW5jdGlvbiBvZShBLGUpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsZV0pLEk9QS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKEkpfWZ1bmN0aW9uIExJKEEsZSx0LEkpe0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihvLEIpe3ZhciBjO3N3aXRjaChvLnR5cGUpe2Nhc2UgdS5UZXh0U3RyZWFtOntsZXQgYT1pdC5lbmNvZGUoby5kYXRhLmRhdGEpLEM9eShBLGEsQiwwKSxRPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07VihBLFEsQik7YnJlYWt9Y2FzZSB1Lkpzb25Db21wYXRpYmxlOntsZXQgYT1pdC5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoby5kYXRhKSksQz15KEEsYSxCLDApLFE9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTtWKEEsUSxCKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgYT1vLmRhdGEuZGF0YSxDPXkoQSxhLEIsMCksUT17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1YoQSxRLEIpO2JyZWFrfWNhc2UgdS5UZXh0RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgdS5CaW5hcnlGaWxlOntBLmZzX3dyaXRlRmlsZShvLmRhdGEucGF0aCxvLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSB1LkltYWdlOntsZXQgYT1vLmRhdGEsQz15KEEsYS5kYXRhLEIsMCksUT15KEEsYS5kaXJlY3Rpb24sQiwxKSxmPXR5cGVvZigoYz1hLm1ldGFkYXRhKT09PW51bGx8fGM9PT12b2lkIDA/dm9pZCAwOmMuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20oYS5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLG09e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLHNpemU6YS5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsbWV0YWRhdGE6Zn07VihBLG0sQik7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBhPW8uZGF0YSxDPXkoQSxhLnBvaW50cyxCLDApLFE9eShBLGEuY2VsbHMsQiwxKSxmPXkoQSxhLnBvaW50RGF0YSxCLDIpLG09eShBLGEuY2VsbERhdGEsQiwzKSx3PXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YH07VihBLHcsQik7YnJlYWt9Y2FzZSB1LlBvbHlEYXRhOntsZXQgYT1vLmRhdGEsQz15KEEsYS5wb2ludHMsQiwwKSxRPXkoQSxhLnZlcnRpY2VzLEIsMSksZj15KEEsYS5saW5lcyxCLDIpLG09eShBLGEucG9seWdvbnMsQiwzKSx3PXkoQSxhLnRyaWFuZ2xlU3RyaXBzLEIsNCksTz15KEEsYS5wb2ludERhdGEsQiw1KSxLPXkoQSxhLnBvaW50RGF0YSxCLDYpLEpBPXtwb2x5RGF0YVR5cGU6YS5wb2x5RGF0YVR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsdmVydGljZXNCdWZmZXJTaXplOmEudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGxpbmVzQnVmZmVyU2l6ZTphLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxwb2x5Z29uc0J1ZmZlclNpemU6YS5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOmEudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7d31gLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke099YCxudW1iZXJPZkNlbGxQaXhlbHM6YS5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtLfWB9O1YoQSxKQSxCKTticmVha31jYXNlIFMuVGV4dDp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkJpbmFyeTp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkltYWdlOntsZXQgYT1vLmRhdGEsQz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTphLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoQykpLGEuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5kYXRhLmJ1ZmZlcikpLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShhLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFMuTWVzaDp7bGV0IGE9by5kYXRhLEM9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZX07aWYoQS5mc19ta2RpcnMoYCR7by5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShDKSksQy5udW1iZXJPZlBvaW50cz4wKXtpZihhLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5wb2ludHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKGEucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShhLnBvaW50RGF0YS5idWZmZXIpKX1pZihDLm51bWJlck9mQ2VsbHM+MCl7aWYoYS5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYoYS5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLEEucmVzZXRNb2R1bGVTdGRvdXQoKSxBLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IHI9QS5zdGFja1NhdmUoKSxpPTA7dHJ5e2k9QS5jYWxsTWFpbihlLnNsaWNlKCkpfWNhdGNoKG8pe3Rocm93IHR5cGVvZiBvPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsQS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsQS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIEEuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsQS5nZXRFeGNlcHRpb25NZXNzYWdlKG8pKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLG99ZmluYWxseXtBLnN0YWNrUmVzdG9yZShyKX1sZXQgZz1BLmdldE1vZHVsZVN0ZG91dCgpLG49QS5nZXRNb2R1bGVTdGRlcnIoKSxFPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZpPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKG8sQil7bGV0IGM9bnVsbDtzd2l0Y2goby50eXBlKXtjYXNlIHUuVGV4dFN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLFEpO2M9e2RhdGE6Z3QuZGVjb2RlKGYpfTticmVha31jYXNlIHUuSnNvbkNvbXBhdGlibGU6e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksZj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsQyxRKTtjPUpTT04ucGFyc2UoZ3QuZGVjb2RlKGYpKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pO2M9e2RhdGE6bnQoQSxDLFEpfTticmVha31jYXNlIHUuVGV4dEZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpBLmZzX3JlYWRGaWxlKG8uZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSB1LkJpbmFyeUZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpIKEEsby5kYXRhLnBhdGgpfTticmVha31jYXNlIHUuSW1hZ2U6e2xldCBDPW9lKEEsQik7Qy5kYXRhPU4oQSxCLDAsQy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQy5kaXJlY3Rpb249TihBLEIsMSxULkZsb2F0NjQpLEMubWV0YWRhdGE9bmV3IE1hcChDLm1ldGFkYXRhKSxjPUM7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkMucG9pbnRzPWQoQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbHM+MD9DLmNlbGxzPU4oQSxCLDEsQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qy5jZWxscz1kKEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiwyLEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPWQoQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1OKEEsQiwzLEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGM9QzticmVha31jYXNlIHUuUG9seURhdGE6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsVC5GbG9hdDMyKTpDLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEMudmVydGljZXNCdWZmZXJTaXplPjA/Qy52ZXJ0aWNlcz1OKEEsQiwxLEYuVUludDMyKTpDLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxDLmxpbmVzQnVmZmVyU2l6ZT4wP0MubGluZXM9TihBLEIsMixGLlVJbnQzMik6Qy5saW5lcz1uZXcgVWludDMyQXJyYXksQy5wb2x5Z29uc0J1ZmZlclNpemU+MD9DLnBvbHlnb25zPU4oQSxCLDMsRi5VSW50MzIpOkMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qy50cmlhbmdsZVN0cmlwcz1OKEEsQiw0LEYuVUludDMyKTpDLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiw1LEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpDLnBvaW50RGF0YT1kKEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxQaXhlbHM+MD9DLmNlbGxEYXRhPU4oQSxCLDYsQy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxjPUM7YnJlYWt9Y2FzZSBTLlRleHQ6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtjPUEuZnNfcmVhZEZpbGUoby5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFMuQmluYXJ5OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Yz1IKEEsby5wYXRoKTticmVha31jYXNlIFMuSW1hZ2U6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgQz1BLmZzX3JlYWRGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLFE9SlNPTi5wYXJzZShDKSxmPUgoQSxgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtRLmRhdGE9ZChRLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGYuYnVmZmVyKTtsZXQgbT1IKEEsYCR7by5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtRLmRpcmVjdGlvbj1kKFQuRmxvYXQ2NCxtLmJ1ZmZlciksYz1RO2JyZWFrfWNhc2UgUy5NZXNoOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEM9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxRPUpTT04ucGFyc2UoQyk7aWYoUS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtRLnBvaW50cz1kKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnRzPWQoUS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihRLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7US5wb2ludERhdGE9ZChRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnREYXRhPWQoUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKFEubnVtYmVyT2ZDZWxscz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO1EuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoUS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtRLmNlbGxEYXRhPWQoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbERhdGE9ZChRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtjPVE7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgYT17dHlwZTpvLnR5cGUsZGF0YTpjfTtFLnB1c2goYSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6ZyxzdGRlcnI6bixvdXRwdXRzOkV9fXZhciB6PUxJO3ZhciBvQT1mdW5jdGlvbihBKXtyZXR1cm4gdGhpcyBpbnN0YW5jZW9mIG9BPyh0aGlzLnY9QSx0aGlzKTpuZXcgb0EoQSl9LE9JPWZ1bmN0aW9uKEEsZSx0KXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIEk9dC5hcHBseShBLGV8fFtdKSxyLGk9W107cmV0dXJuIHI9e30sZygibmV4dCIpLGcoInRocm93IiksZygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scjtmdW5jdGlvbiBnKGEpe0lbYV0mJihyW2FdPWZ1bmN0aW9uKEMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihRLGYpe2kucHVzaChbYSxDLFEsZl0pPjF8fG4oYSxDKX0pfSl9ZnVuY3Rpb24gbihhLEMpe3RyeXtFKElbYV0oQykpfWNhdGNoKFEpe2MoaVswXVszXSxRKX19ZnVuY3Rpb24gRShhKXthLnZhbHVlIGluc3RhbmNlb2Ygb0E/UHJvbWlzZS5yZXNvbHZlKGEudmFsdWUudikudGhlbihvLEIpOmMoaVswXVsyXSxhKX1mdW5jdGlvbiBvKGEpe24oIm5leHQiLGEpfWZ1bmN0aW9uIEIoYSl7bigidGhyb3ciLGEpfWZ1bmN0aW9uIGMoYSxDKXthKEMpLGkuc2hpZnQoKSxpLmxlbmd0aCYmbihpWzBdWzBdLGlbMF1bMV0pfX0sSkk9ZnVuY3Rpb24oQSl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBlPUFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdLHQ7cmV0dXJuIGU/ZS5jYWxsKEEpOihBPXR5cGVvZiBfX3ZhbHVlcz09ImZ1bmN0aW9uIj9fX3ZhbHVlcyhBKTpBW1N5bWJvbC5pdGVyYXRvcl0oKSx0PXt9LEkoIm5leHQiKSxJKCJ0aHJvdyIpLEkoInJldHVybiIpLHRbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHQpO2Z1bmN0aW9uIEkoaSl7dFtpXT1BW2ldJiZmdW5jdGlvbihnKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obixFKXtnPUFbaV0oZykscihuLEUsZy5kb25lLGcudmFsdWUpfSl9fWZ1bmN0aW9uIHIoaSxnLG4sRSl7UHJvbWlzZS5yZXNvbHZlKEUpLnRoZW4oZnVuY3Rpb24obyl7aSh7dmFsdWU6byxkb25lOm59KX0sZyl9fTtmdW5jdGlvbiBNSShBKXtyZXR1cm4gT0kodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24qKCl7Zm9yKGxldCB0PTA7dDxMQS5sZW5ndGg7dCsrKXtsZXQgST1MQVt0XSsiLXJlYWQtaW1hZ2UiLHI9eWllbGQgb0EoRyhJLEEuY29uZmlnLmltYWdlSU9VcmwpKTt5aWVsZCB5aWVsZCBvQShyKX19KX1hc3luYyBmdW5jdGlvbiBiSShBLGUpe3ZhciB0LEk7aWYoQS5taW1lVHlwZSYmaWUuaGFzKEEubWltZVR5cGUpKXtsZXQgbj1pZS5nZXQoQS5taW1lVHlwZSkrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLmltYWdlSU9VcmwpfWxldCByPWtBKEEuZmlsZU5hbWUpO2lmKGdlLmhhcyhyKSl7bGV0IG49Z2UuZ2V0KHIpK2U7cmV0dXJuIGF3YWl0IEcobixBLmNvbmZpZy5pbWFnZUlPVXJsKX1mb3IobGV0IG49MDtuPExBLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsSkkoTUkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBuZT1iSTt2YXIgSEk9bmV3IE1hcChbXSksYWU9SEk7dmFyIFlJPW5ldyBNYXAoW1sidnRrIiwiVlRLUG9seURhdGFNZXNoSU8iXSxbIlZUSyIsIlZUS1BvbHlEYXRhTWVzaElPIl0sWyJieXUiLCJCWVVNZXNoSU8iXSxbIkJZVSIsIkJZVU1lc2hJTyJdLFsiZnNhIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIl0sWyJGU0EiLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iXSxbImZzYiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIkZTQiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIm9iaiIsIk9CSk1lc2hJTyJdLFsiT0JKIiwiT0JKTWVzaElPIl0sWyJvZmYiLCJPRkZNZXNoSU8iXSxbIk9GRiIsIk9GRk1lc2hJTyJdLFsic3RsIiwiU1RMTWVzaElPIl0sWyJTVEwiLCJTVExNZXNoSU8iXSxbInN3YyIsIlNXQ01lc2hJTyJdLFsiU1dDIiwiU1dDTWVzaElPIl0sWyJpd20iLCJXYXNtTWVzaElPIl0sWyJpd20uY2JvciIsIldhc21NZXNoSU8iXSxbIml3bS5jYm9yLnpzdCIsIldhc21ac3RkTWVzaElPIl1dKSxzZT1ZSTt2YXIgcUk9WyJCWVVNZXNoSU8iLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIiwiT0JKTWVzaElPIiwiT0ZGTWVzaElPIiwiU1RMTWVzaElPIiwiU1dDTWVzaElPIiwiVlRLUG9seURhdGFNZXNoSU8iLCJXYXNtTWVzaElPIiwiV2FzbVpzdGRNZXNoSU8iXSxPQT1xSTt2YXIgbkE9ZnVuY3Rpb24oQSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBuQT8odGhpcy52PUEsdGhpcyk6bmV3IG5BKEEpfSxUST1mdW5jdGlvbihBLGUsdCl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBJPXQuYXBwbHkoQSxlfHxbXSkscixpPVtdO3JldHVybiByPXt9LGcoIm5leHQiKSxnKCJ0aHJvdyIpLGcoInJldHVybiIpLHJbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHI7ZnVuY3Rpb24gZyhhKXtJW2FdJiYoclthXT1mdW5jdGlvbihDKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oUSxmKXtpLnB1c2goW2EsQyxRLGZdKT4xfHxuKGEsQyl9KX0pfWZ1bmN0aW9uIG4oYSxDKXt0cnl7RShJW2FdKEMpKX1jYXRjaChRKXtjKGlbMF1bM10sUSl9fWZ1bmN0aW9uIEUoYSl7YS52YWx1ZSBpbnN0YW5jZW9mIG5BP1Byb21pc2UucmVzb2x2ZShhLnZhbHVlLnYpLnRoZW4obyxCKTpjKGlbMF1bMl0sYSl9ZnVuY3Rpb24gbyhhKXtuKCJuZXh0IixhKX1mdW5jdGlvbiBCKGEpe24oInRocm93IixhKX1mdW5jdGlvbiBjKGEsQyl7YShDKSxpLnNoaWZ0KCksaS5sZW5ndGgmJm4oaVswXVswXSxpWzBdWzFdKX19LEtJPWZ1bmN0aW9uKEEpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgZT1BW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSx0O3JldHVybiBlP2UuY2FsbChBKTooQT10eXBlb2YgX192YWx1ZXM9PSJmdW5jdGlvbiI/X192YWx1ZXMoQSk6QVtTeW1ib2wuaXRlcmF0b3JdKCksdD17fSxJKCJuZXh0IiksSSgidGhyb3ciKSxJKCJyZXR1cm4iKSx0W1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0KTtmdW5jdGlvbiBJKGkpe3RbaV09QVtpXSYmZnVuY3Rpb24oZyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4sRSl7Zz1BW2ldKGcpLHIobixFLGcuZG9uZSxnLnZhbHVlKX0pfX1mdW5jdGlvbiByKGksZyxuLEUpe1Byb21pc2UucmVzb2x2ZShFKS50aGVuKGZ1bmN0aW9uKG8pe2koe3ZhbHVlOm8sZG9uZTpufSl9LGcpfX07ZnVuY3Rpb24geEkoQSl7cmV0dXJuIFRJKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKigpe2ZvcihsZXQgdD0wO3Q8T0EubGVuZ3RoO3QrKyl7bGV0IEk9T0FbdF0rIi1yZWFkLW1lc2giLHI9eWllbGQgbkEoRyhJLEEuY29uZmlnLm1lc2hJT1VybCkpO3lpZWxkIHlpZWxkIG5BKHIpfX0pfWFzeW5jIGZ1bmN0aW9uIFBJKEEsZSl7dmFyIHQsSTtpZihBLm1pbWVUeXBlJiZhZS5oYXMoQS5taW1lVHlwZSkpe2xldCBuPWFlLmdldChBLm1pbWVUeXBlKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1sZXQgcj1rQShBLmZpbGVOYW1lKTtpZihzZS5oYXMocikpe2xldCBuPXNlLmdldChyKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1mb3IobGV0IG49MDtuPE9BLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsS0koeEkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBDZT1QSTt2YXIgV0k9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIGpJKEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCB0PTA7dDxBLmxlbmd0aDt0Kyspe2xldCBJPVpJKEFbdF0pO0khPT1udWxsJiZlLnB1c2goSSl9cmV0dXJuIGV9ZnVuY3Rpb24gWkkoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgZT1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD9lPUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKGU9QSksV0kmJmUgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmV9dmFyIGF0PWpJO2Z1bmN0aW9uIF9JKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciBCZT1fSTtmdW5jdGlvbiBWSShBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgUWU9Vkk7ZnVuY3Rpb24gekkoQSl7cmV0dXJuW0EucG9pbnRzLEEudmVydGljZXMsQS5saW5lcyxBLnBvbHlnb25zLEEudHJpYW5nbGVTdHJpcHMsQS5wb2ludERhdGEsQS5jZWxsRGF0YV19dmFyIHN0PXpJO2FzeW5jIGZ1bmN0aW9uIFhJKEEsZSx0LEkpe2xldCByPXooQSxlLHQsSSksaT1bXTtyZXR1cm4gci5vdXRwdXRzJiZyLm91dHB1dHMuZm9yRWFjaChmdW5jdGlvbihnKXtpZihnLnR5cGU9PT11LkJpbmFyeVN0cmVhbXx8Zy50eXBlPT09dS5CaW5hcnlGaWxlKXtsZXQgbj1nLmRhdGE7aS5wdXNoKG4pfWVsc2UgaWYoZy50eXBlPT09dS5JbWFnZSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5CZShuKSl9ZWxzZSBpZihnLnR5cGU9PT11Lk1lc2gpe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uUWUobikpfWVsc2UgaWYoZy50eXBlPT09dS5Qb2x5RGF0YSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5zdChuKSl9ZWxzZSBpZihnLnR5cGU9PT1TLkJpbmFyeSl7bGV0IG49Zy5kYXRhO2kucHVzaChuKX1lbHNlIGlmKGcudHlwZT09PVMuSW1hZ2Upe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uQmUobikpfWVsc2UgaWYoZy50eXBlPT09Uy5NZXNoKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLlFlKG4pKX19KSxIQShyLGF0KGkpKX12YXIgWT1YSTt2YXIgdkk9e21lc2hUb1BvbHlEYXRhOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkpe2xldCByPWF3YWl0IEcoIm1lc2gtdG8tcG9seWRhdGEiLEEubWVzaElPVXJsKTtyZXR1cm4gWShyLGUsdCxJKX0scG9seURhdGFUb01lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSl7bGV0IHI9YXdhaXQgRygicG9seWRhdGEtdG8tbWVzaCIsQS5tZXNoSU9VcmwpO3JldHVybiBZKHIsZSx0LEkpfSxyZWFkSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi1yZWFkLWltYWdlIik7cmV0dXJuIFkoZyxJLHIsaSl9LHdyaXRlSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1pbWFnZSIpO3JldHVybiBZKGcsSSxyLGkpfSxyZWFkTWVzaDphc3luYyBmdW5jdGlvbihBLGUsdCxJLHIsaSl7bGV0IGc9YXdhaXQgQ2Uoe2ZpbGVOYW1lOnQsbWltZVR5cGU6ZSxjb25maWc6QSxhcmdzOkksb3V0cHV0czpyLGlucHV0czppfSwiLXJlYWQtbWVzaCIpO3JldHVybiBZKGcsSSxyLGkpfSx3cml0ZU1lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IENlKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1tZXNoIik7cmV0dXJuIFkoZyxJLHIsaSl9LHJ1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz10eXBlb2YgQVt0XT4idSI/dDpBW3RdLG49YXdhaXQgRyhlLGcpO3JldHVybiBZKG4sSSxyLGkpfX07RUEodkkpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7dXQoQnQpO2V4cG9ydHskciBhcyBhcHBseVByZXNlbnRhdGlvblN0YXRlVG9JbWFnZSxUIGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLE8gYXMgZ2V0UGlwZWxpbmVzQmFzZVVybCxlbiBhcyByZWFkRGljb21FbmNhcHN1bGF0ZWRQZGYsc24gYXMgcmVhZERpY29tVGFncyxjbiBhcyByZWFkSW1hZ2VEaWNvbUZpbGVTZXJpZXMsb2UgYXMgcmVhZEltYWdlRGljb21GaWxlU2VyaWVzV29ya2VyRnVuY3Rpb24sdXQgYXMgc2V0UGlwZWxpbmVXb3JrZXJVcmwsSXMgYXMgc2V0UGlwZWxpbmVzQmFzZVVybCxybiBhcyBzdHJ1Y3R1cmVkUmVwb3J0VG9IdG1sLGFuIGFzIHN0cnVjdHVyZWRSZXBvcnRUb1RleHR9OwovKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOgoKY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczoKICAoKioKICAgKiBAbGljZW5zZQogICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMKICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMAogICAqKQoqLwo=""" +default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/dicom/python/itkwasm-dicom-emscripten/pyproject.toml b/packages/dicom/python/itkwasm-dicom-emscripten/pyproject.toml index 4d51ddf77..f25d8729f 100644 --- a/packages/dicom/python/itkwasm-dicom-emscripten/pyproject.toml +++ b/packages/dicom/python/itkwasm-dicom-emscripten/pyproject.toml @@ -22,6 +22,7 @@ classifiers = [ "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", ] keywords = [ "itkwasm", @@ -31,7 +32,7 @@ keywords = [ requires-python = ">=3.8" dependencies = [ - "itkwasm >= 1.0.b131", + "itkwasm >= 1.0.b145", ] [tool.hatch.version] diff --git a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py index ce1305bf4..ba7be38e4 100644 --- a/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py +++ b/packages/dicom/python/itkwasm-dicom-wasi/itkwasm_dicom_wasi/_version.py @@ -1 +1 @@ -__version__ = "4.0.0" +__version__ = "5.0.0" diff --git a/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py index ce1305bf4..ba7be38e4 100644 --- a/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py +++ b/packages/dicom/python/itkwasm-dicom/itkwasm_dicom/_version.py @@ -1 +1 @@ -__version__ = "4.0.0" +__version__ = "5.0.0" diff --git a/packages/dicom/typescript/build/rollup.browser.config.js b/packages/dicom/typescript/build/rollup.browser.config.js deleted file mode 100644 index ac03845a3..000000000 --- a/packages/dicom/typescript/build/rollup.browser.config.js +++ /dev/null @@ -1,51 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import copy from 'rollup-plugin-copy' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import nodePolyfills from 'rollup-plugin-polyfill-node' -import ignore from 'rollup-plugin-ignore' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import json from '@rollup/plugin-json' -import path from 'path' - -const itkConfig = './src/itkConfig.js' -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index.ts', - output: [ - { - file: `./dist/bundles/${bundleName}.js`, - format: 'es', - sourcemap: true, - // plugins: [terser(),], - }, - ], - plugins: [ - copy({ - targets: [ - { src: 'node_modules/itk-wasm/dist/web-workers/bundles/pipeline.worker.js', dest: 'dist/web-workers/' }, - ], - hook: 'writeBundle' - }), - ignore(['crypto']), - nodeResolve({ - preferBuiltins: false, - browser: true, - }), - commonjs({ - transformMixedEsModules: true - }), - nodePolyfills(), - typescript(), - json(), - ], - resolve: { - // where itk-wasm code has 'import ../itkConfig.js` point to the path of itkConfig - alias: { - '../itkConfig.js': itkConfig, - '../../itkConfig.js': itkConfig - } - } -} diff --git a/packages/dicom/typescript/build/rollup.node.config.js b/packages/dicom/typescript/build/rollup.node.config.js deleted file mode 100644 index 8b0695e18..000000000 --- a/packages/dicom/typescript/build/rollup.node.config.js +++ /dev/null @@ -1,32 +0,0 @@ -import { nodeResolve } from '@rollup/plugin-node-resolve' -import typescript from '@rollup/plugin-typescript' -import commonjs from '@rollup/plugin-commonjs' -import json from '@rollup/plugin-json' -import terser from '@rollup/plugin-terser' -import packageJson from '../package.json' assert { type: 'json' } -import path from 'path' - -const bundleName = path.basename(packageJson.name) - -export default { - input: './src/index-node.ts', - output: [ - { - file: `./dist/bundles/${bundleName}-node.js`, - format: 'es', - sourcemap: true, - plugins: [terser(),], - }, - ], - plugins: [ - commonjs({ - transformMixedEsModules: true - }), - nodeResolve({ - preferBuiltins: true, - browser: false, - }), - typescript(), - json(), - ], -} diff --git a/packages/dicom/typescript/build/vite.config.js b/packages/dicom/typescript/build/vite.config.js index 222e14626..5266d1417 100644 --- a/packages/dicom/typescript/build/vite.config.js +++ b/packages/dicom/typescript/build/vite.config.js @@ -8,11 +8,18 @@ export default defineConfig({ outDir: '../../../demo-app', emptyOutDir: true, }, + worker: { + format: 'es' + }, + optimizeDeps: { + exclude: ['itk-wasm', '@itk-wasm/image-io'] + }, plugins: [ // put lazy loaded JavaScript and Wasm bundles in dist directory viteStaticCopy({ targets: [ { src: '../../../dist/pipelines/*', dest: 'pipelines' }, + { src: '../../../node_modules/@itk-wasm/image-io/dist/pipelines/*.{js,wasm,wasm.zst}', dest: 'pipelines' }, ], }) ], diff --git a/packages/dicom/typescript/package.json b/packages/dicom/typescript/package.json index 9a97505a5..93d2aaf60 100644 --- a/packages/dicom/typescript/package.json +++ b/packages/dicom/typescript/package.json @@ -1,16 +1,16 @@ { "name": "@itk-wasm/dicom", - "version": "4.0.0", + "version": "5.0.0", "description": "Read files and images related to DICOM file format.", "type": "module", - "module": "./dist/bundles/dicom.js", - "types": "./dist/src/index.d.ts", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", "exports": { ".": { - "types": "./dist/src/index.d.ts", - "browser": "./dist/bundles/dicom.js", - "node": "./dist/bundles/dicom-node.js", - "default": "./dist/bundles/dicom.js" + "types": "./dist/index.d.ts", + "browser": "./dist/index.js", + "node": "./dist/index-node.js", + "default": "./dist/index.js" } }, "scripts": { @@ -25,9 +25,9 @@ "cypress:open": "npx cypress open", "cypress:runChrome": "npx cypress run --browser chrome", "cypress:runFirefox": "npx cypress run --browser firefox", - "build": "npm run build:tsc && npm run build:node && npm run build:browser && npm run build:demo", - "build:node": "rollup -c ./build/rollup.node.config.js", - "build:browser": "rollup -c ./build/rollup.browser.config.js", + "build": "npm run build:tsc && npm run build:browser:workerEmbedded && npm run build:browser:workerEmbeddedMin && npm run build:demo", + "build:browser:workerEmbedded": "esbuild --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.js ./src/index-worker-embedded.ts", + "build:browser:workerEmbeddedMin": "esbuild --minify --loader:.worker.js=dataurl --bundle --format=esm --outfile=./dist/bundle/index-worker-embedded.min.js ./src/index-worker-embedded.min.ts", "build:tsc": "tsc --pretty", "build:demo": "npm run copyShoelaceAssets && vite -c build/vite.config.js build" }, @@ -39,30 +39,19 @@ "author": "", "license": "Apache-2.0", "dependencies": { - "itk-wasm": "^1.0.0-b.149" + "itk-wasm": "^1.0.0-b.154" }, "devDependencies": { - "@rollup/plugin-commonjs": "^24.0.0", - "@rollup/plugin-json": "^6.0.0", - "@rollup/plugin-node-resolve": "^15.1.0", - "@rollup/plugin-terser": "^0.4.0", - "@rollup/plugin-typescript": "^11.1.1", + "@itk-wasm/image-io": "^0.4.0", "@shoelace-style/shoelace": "^2.5.2", "@types/node": "^20.2.5", "ava": "^5.1.0", "cypress": "^12.17.2", - "itk-image-io": "^1.0.0-b.149", - "rollup": "^3.9.0", - "rollup-plugin-copy": "^3.4.0", - "rollup-plugin-ignore": "^1.0.10", - "rollup-plugin-polyfill-node": "^0.12.0", "shx": "^0.3.4", "start-server-and-test": "^2.0.0", - "supports-color": "^9.3.1", - "tslib": "^2.5.2", "typescript": "^5.1.6", - "vite": "^4.1.5", - "vite-plugin-static-copy": "^0.14.0" + "vite": "^4.4.11", + "vite-plugin-static-copy": "^0.17.0" }, "repository": { "type": "git", diff --git a/packages/dicom/typescript/pnpm-lock.yaml b/packages/dicom/typescript/pnpm-lock.yaml index 30c259d02..c8723b112 100644 --- a/packages/dicom/typescript/pnpm-lock.yaml +++ b/packages/dicom/typescript/pnpm-lock.yaml @@ -6,25 +6,13 @@ settings: dependencies: itk-wasm: - specifier: ^1.0.0-b.138 - version: 1.0.0-b.146 + specifier: ^1.0.0-b.154 + version: 1.0.0-b.154 devDependencies: - '@rollup/plugin-commonjs': - specifier: ^24.0.0 - version: 24.0.1(rollup@3.18.0) - '@rollup/plugin-json': - specifier: ^6.0.0 - version: 6.0.0(rollup@3.18.0) - '@rollup/plugin-node-resolve': - specifier: ^15.1.0 - version: 15.1.0(rollup@3.18.0) - '@rollup/plugin-terser': + '@itk-wasm/image-io': specifier: ^0.4.0 - version: 0.4.3(rollup@3.18.0) - '@rollup/plugin-typescript': - specifier: ^11.1.1 - version: 11.1.2(rollup@3.18.0)(tslib@2.6.1)(typescript@5.1.6) + version: 0.4.0 '@shoelace-style/shoelace': specifier: ^2.5.2 version: 2.6.0 @@ -33,46 +21,25 @@ devDependencies: version: 20.4.8 ava: specifier: ^5.1.0 - version: 5.2.0(supports-color@9.3.1) + version: 5.2.0 cypress: specifier: ^12.17.2 version: 12.17.3 - itk-image-io: - specifier: ^1.0.0-b.130 - version: 1.0.0-b.146 - rollup: - specifier: ^3.9.0 - version: 3.18.0 - rollup-plugin-copy: - specifier: ^3.4.0 - version: 3.4.0 - rollup-plugin-ignore: - specifier: ^1.0.10 - version: 1.0.10 - rollup-plugin-polyfill-node: - specifier: ^0.12.0 - version: 0.12.0(rollup@3.18.0) shx: specifier: ^0.3.4 version: 0.3.4 start-server-and-test: specifier: ^2.0.0 - version: 2.0.0(supports-color@9.3.1) - supports-color: - specifier: ^9.3.1 - version: 9.3.1 - tslib: - specifier: ^2.5.2 - version: 2.6.1 + version: 2.0.0 typescript: specifier: ^5.1.6 version: 5.1.6 vite: - specifier: ^4.1.5 - version: 4.1.5(@types/node@20.4.8) + specifier: ^4.4.11 + version: 4.5.0(@types/node@20.4.8) vite-plugin-static-copy: - specifier: ^0.14.0 - version: 0.14.0(vite@4.1.5) + specifier: ^0.17.0 + version: 0.17.0(vite@4.5.0) packages: @@ -127,8 +94,8 @@ packages: - supports-color dev: true - /@esbuild/android-arm64@0.16.17: - resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} + /@esbuild/android-arm64@0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} engines: {node: '>=12'} cpu: [arm64] os: [android] @@ -136,8 +103,8 @@ packages: dev: true optional: true - /@esbuild/android-arm@0.16.17: - resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} + /@esbuild/android-arm@0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} engines: {node: '>=12'} cpu: [arm] os: [android] @@ -145,8 +112,8 @@ packages: dev: true optional: true - /@esbuild/android-x64@0.16.17: - resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} + /@esbuild/android-x64@0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -154,8 +121,8 @@ packages: dev: true optional: true - /@esbuild/darwin-arm64@0.16.17: - resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} + /@esbuild/darwin-arm64@0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} engines: {node: '>=12'} cpu: [arm64] os: [darwin] @@ -163,8 +130,8 @@ packages: dev: true optional: true - /@esbuild/darwin-x64@0.16.17: - resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} + /@esbuild/darwin-x64@0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} engines: {node: '>=12'} cpu: [x64] os: [darwin] @@ -172,8 +139,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-arm64@0.16.17: - resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} + /@esbuild/freebsd-arm64@0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} engines: {node: '>=12'} cpu: [arm64] os: [freebsd] @@ -181,8 +148,8 @@ packages: dev: true optional: true - /@esbuild/freebsd-x64@0.16.17: - resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} + /@esbuild/freebsd-x64@0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} engines: {node: '>=12'} cpu: [x64] os: [freebsd] @@ -190,8 +157,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm64@0.16.17: - resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} + /@esbuild/linux-arm64@0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} engines: {node: '>=12'} cpu: [arm64] os: [linux] @@ -199,8 +166,8 @@ packages: dev: true optional: true - /@esbuild/linux-arm@0.16.17: - resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} + /@esbuild/linux-arm@0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} engines: {node: '>=12'} cpu: [arm] os: [linux] @@ -208,8 +175,8 @@ packages: dev: true optional: true - /@esbuild/linux-ia32@0.16.17: - resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} + /@esbuild/linux-ia32@0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} engines: {node: '>=12'} cpu: [ia32] os: [linux] @@ -217,8 +184,8 @@ packages: dev: true optional: true - /@esbuild/linux-loong64@0.16.17: - resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} + /@esbuild/linux-loong64@0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} engines: {node: '>=12'} cpu: [loong64] os: [linux] @@ -226,8 +193,8 @@ packages: dev: true optional: true - /@esbuild/linux-mips64el@0.16.17: - resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} + /@esbuild/linux-mips64el@0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} engines: {node: '>=12'} cpu: [mips64el] os: [linux] @@ -235,8 +202,8 @@ packages: dev: true optional: true - /@esbuild/linux-ppc64@0.16.17: - resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} + /@esbuild/linux-ppc64@0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} engines: {node: '>=12'} cpu: [ppc64] os: [linux] @@ -244,8 +211,8 @@ packages: dev: true optional: true - /@esbuild/linux-riscv64@0.16.17: - resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} + /@esbuild/linux-riscv64@0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} engines: {node: '>=12'} cpu: [riscv64] os: [linux] @@ -253,8 +220,8 @@ packages: dev: true optional: true - /@esbuild/linux-s390x@0.16.17: - resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} + /@esbuild/linux-s390x@0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} engines: {node: '>=12'} cpu: [s390x] os: [linux] @@ -262,8 +229,8 @@ packages: dev: true optional: true - /@esbuild/linux-x64@0.16.17: - resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} + /@esbuild/linux-x64@0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} engines: {node: '>=12'} cpu: [x64] os: [linux] @@ -271,8 +238,8 @@ packages: dev: true optional: true - /@esbuild/netbsd-x64@0.16.17: - resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} + /@esbuild/netbsd-x64@0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -280,8 +247,8 @@ packages: dev: true optional: true - /@esbuild/openbsd-x64@0.16.17: - resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} + /@esbuild/openbsd-x64@0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] @@ -289,8 +256,8 @@ packages: dev: true optional: true - /@esbuild/sunos-x64@0.16.17: - resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} + /@esbuild/sunos-x64@0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} engines: {node: '>=12'} cpu: [x64] os: [sunos] @@ -298,8 +265,8 @@ packages: dev: true optional: true - /@esbuild/win32-arm64@0.16.17: - resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} + /@esbuild/win32-arm64@0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} engines: {node: '>=12'} cpu: [arm64] os: [win32] @@ -307,8 +274,8 @@ packages: dev: true optional: true - /@esbuild/win32-ia32@0.16.17: - resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} + /@esbuild/win32-ia32@0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} engines: {node: '>=12'} cpu: [ia32] os: [win32] @@ -316,8 +283,8 @@ packages: dev: true optional: true - /@esbuild/win32-x64@0.16.17: - resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} + /@esbuild/win32-x64@0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} engines: {node: '>=12'} cpu: [x64] os: [win32] @@ -352,41 +319,12 @@ packages: '@hapi/hoek': 9.3.0 dev: true - /@jridgewell/gen-mapping@0.3.2: - resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - - /@jridgewell/resolve-uri@3.1.0: - resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - dev: true - - /@jridgewell/source-map@0.3.5: - resolution: {integrity: sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.2 - '@jridgewell/trace-mapping': 0.3.17 - dev: true - - /@jridgewell/sourcemap-codec@1.4.14: - resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true - - /@jridgewell/trace-mapping@0.3.17: - resolution: {integrity: sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==} + /@itk-wasm/image-io@0.4.0: + resolution: {integrity: sha512-2bZdKCRIvWE+sQXJFjzjwgMQZnrqKqzy+yecee6/9IblqhBu76bcs5tdjcAwlC05LmK4HtntC3BwOLLwcA1KpQ==} dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 + itk-wasm: 1.0.0-b.154 + transitivePeerDependencies: + - debug dev: true /@lit-labs/react@1.2.1: @@ -424,120 +362,6 @@ packages: fastq: 1.13.0 dev: true - /@rollup/plugin-commonjs@24.0.1(rollup@3.18.0): - resolution: {integrity: sha512-15LsiWRZk4eOGqvrJyu3z3DaBu5BhXIMeWnijSRvd8irrrg9SHpQ1pH+BUK4H6Z9wL9yOxZJMTLU+Au86XHxow==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.68.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.18.0) - commondir: 1.0.1 - estree-walker: 2.0.2 - glob: 8.1.0 - is-reference: 1.2.1 - magic-string: 0.27.0 - rollup: 3.18.0 - dev: true - - /@rollup/plugin-inject@5.0.3(rollup@3.18.0): - resolution: {integrity: sha512-411QlbL+z2yXpRWFXSmw/teQRMkXcAAC8aYTemc15gwJRpvEVDQwoe+N/HTFD8RFG8+88Bme9DK2V9CVm7hJdA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.18.0) - estree-walker: 2.0.2 - magic-string: 0.27.0 - rollup: 3.18.0 - dev: true - - /@rollup/plugin-json@6.0.0(rollup@3.18.0): - resolution: {integrity: sha512-i/4C5Jrdr1XUarRhVu27EEwjt4GObltD7c+MkCIpO2QIbojw8MUs+CCTqOphQi3Qtg1FLmYt+l+6YeoIf51J7w==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.18.0) - rollup: 3.18.0 - dev: true - - /@rollup/plugin-node-resolve@15.1.0(rollup@3.18.0): - resolution: {integrity: sha512-xeZHCgsiZ9pzYVgAo9580eCGqwh/XCEUM9q6iQfGNocjgkufHAqC3exA+45URvhiYV8sBF9RlBai650eNs7AsA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.78.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.18.0) - '@types/resolve': 1.20.2 - deepmerge: 4.2.2 - is-builtin-module: 3.2.1 - is-module: 1.0.0 - resolve: 1.22.1 - rollup: 3.18.0 - dev: true - - /@rollup/plugin-terser@0.4.3(rollup@3.18.0): - resolution: {integrity: sha512-EF0oejTMtkyhrkwCdg0HJ0IpkcaVg1MMSf2olHb2Jp+1mnLM04OhjpJWGma4HobiDTF0WCyViWuvadyE9ch2XA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.x || ^3.x - peerDependenciesMeta: - rollup: - optional: true - dependencies: - rollup: 3.18.0 - serialize-javascript: 6.0.1 - smob: 1.4.0 - terser: 5.19.2 - dev: true - - /@rollup/plugin-typescript@11.1.2(rollup@3.18.0)(tslib@2.6.1)(typescript@5.1.6): - resolution: {integrity: sha512-0ghSOCMcA7fl1JM+0gYRf+Q/HWyg+zg7/gDSc+fRLmlJWcW5K1I+CLRzaRhXf4Y3DRyPnnDo4M2ktw+a6JcDEg==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^2.14.0||^3.0.0 - tslib: '*' - typescript: '>=3.7.0' - peerDependenciesMeta: - rollup: - optional: true - tslib: - optional: true - dependencies: - '@rollup/pluginutils': 5.0.2(rollup@3.18.0) - resolve: 1.22.1 - rollup: 3.18.0 - tslib: 2.6.1 - typescript: 5.1.6 - dev: true - - /@rollup/pluginutils@5.0.2(rollup@3.18.0): - resolution: {integrity: sha512-pTd9rIsP92h+B6wWwFbW8RkZv4hiR/xKsqre4SIuAOaOEQRxi0lqLke9k2/7WegC85GgUs9pjmOjCUi3In4vwA==} - engines: {node: '>=14.0.0'} - peerDependencies: - rollup: ^1.20.0||^2.0.0||^3.0.0 - peerDependenciesMeta: - rollup: - optional: true - dependencies: - '@types/estree': 1.0.0 - estree-walker: 2.0.2 - picomatch: 2.3.1 - rollup: 3.18.0 - dev: true - /@shoelace-style/animations@1.1.0: resolution: {integrity: sha512-Be+cahtZyI2dPKRm8EZSx3YJQ+jLvEcn3xzRP7tM4tqBnvd/eW/64Xh0iOf0t2w5P8iJKfdBbpVNE9naCaOf2g==} dev: true @@ -574,33 +398,12 @@ packages: resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} dev: true - /@thewtex/zstddec@0.1.2: - resolution: {integrity: sha512-Bv50pouFqlmIZDcAA2Nrpk9tjJpAPlqHHeD5h0noK+oNXMimrZ/hMbJK2N09Svr6TI/S6nT63dzkWoim4ZzTuw==} + /@thewtex/zstddec@0.2.0: + resolution: {integrity: sha512-lIS+smrfa48WGlDVQSQSm0jBnwVp5XmfGJWU9q0J0fRFY9ohzK4s27Zg2SFMb1NWMp9RiANAdK+/q86EBGWR1Q==} /@types/emscripten@1.39.6: resolution: {integrity: sha512-H90aoynNhhkQP6DRweEjJp5vfUVdIj7tdPLsu7pq89vODD/lcugKfZOsfgwpvM6XUewEp2N5dCg1Uf3Qe55Dcg==} - /@types/estree@1.0.0: - resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==} - dev: true - - /@types/fs-extra@8.1.2: - resolution: {integrity: sha512-SvSrYXfWSc7R4eqnOzbQF4TZmfpNSM9FrSWLU3EUnWBuyZqNBOrv1B1JA3byUDPUl9z4Ab3jeZG2eDdySlgNMg==} - dependencies: - '@types/node': 20.4.8 - dev: true - - /@types/glob@7.2.0: - resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} - dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 20.4.8 - dev: true - - /@types/minimatch@5.1.2: - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} - dev: true - /@types/node@16.18.39: resolution: {integrity: sha512-8q9ZexmdYYyc5/cfujaXb4YOucpQxAV4RMG0himLyDUOEr8Mr79VrqsFI+cQ2M2h89YIuy95lbxuYjxT4Hk4kQ==} dev: true @@ -609,10 +412,6 @@ packages: resolution: {integrity: sha512-0mHckf6D2DiIAzh8fM8f3HQCvMKDpK94YQ0DSVkfWTG9BZleYIWudw9cJxX8oCk9bM+vAkDyujDV6dmKHbvQpg==} dev: true - /@types/resolve@1.20.2: - resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - dev: true - /@types/sinonjs__fake-timers@8.1.1: resolution: {integrity: sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==} dev: true @@ -721,11 +520,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true - /arrgv@1.0.2: resolution: {integrity: sha512-a4eg4yhp7mmruZDQFqVMlxNRFGi/i1r87pt8SDHy0/I8PqSXoUTlWZRdAZo0VXgvEARcujbtTk8kiZRi1uDGRw==} engines: {node: '>=8.0.0'} @@ -764,7 +558,7 @@ packages: engines: {node: '>= 4.0.0'} dev: true - /ava@5.2.0(supports-color@9.3.1): + /ava@5.2.0: resolution: {integrity: sha512-W8yxFXJr/P68JP55eMpQIa6AiXhCX3VeuajM8nolyWNExcMDD6rnIWKTjw0B/+GkFHBIaN6Jd0LtcMThcoqVfg==} engines: {node: '>=14.19 <15 || >=16.15 <17 || >=18'} hasBin: true @@ -792,7 +586,7 @@ packages: common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.3.4(supports-color@9.3.1) + debug: 4.3.4(supports-color@8.1.1) del: 7.0.0 emittery: 1.0.1 figures: 5.0.0 @@ -902,10 +696,6 @@ packages: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true - /buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} dependencies: @@ -913,11 +703,6 @@ packages: ieee754: 1.2.1 dev: true - /builtin-modules@3.3.0: - resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} - engines: {node: '>=6'} - dev: true - /cachedir@2.3.0: resolution: {integrity: sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==} engines: {node: '>=6'} @@ -1068,10 +853,6 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true - /colorette@1.4.0: - resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - dev: true - /colorette@2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} dev: true @@ -1082,9 +863,8 @@ packages: dependencies: delayed-stream: 1.0.0 - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - dev: true + /comlink@4.4.1: + resolution: {integrity: sha512-+1dlx0aY5Jo1vHy/tSsIGpSkN4tS9rZSW8FIhG0JH/crs9wwweswIo/POr451r7bZww3hFbPAKnTpimzL/mm4Q==} /commander@6.2.1: resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} @@ -1104,10 +884,6 @@ packages: engines: {node: '>=4.0.0'} dev: true - /commondir@1.0.1: - resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - dev: true - /composed-offset-position@0.0.4: resolution: {integrity: sha512-vMlvu1RuNegVE0YsCDSV/X4X10j56mq7PCIyOKK74FxkXzGLwhOUmdkJLSdOBOMwWycobGUMgft2lp+YgTe8hw==} dev: true @@ -1246,24 +1022,6 @@ packages: dependencies: ms: 2.1.2 supports-color: 8.1.1 - dev: true - - /debug@4.3.4(supports-color@9.3.1): - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - supports-color: 9.3.1 - - /deepmerge@4.2.2: - resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} - engines: {node: '>=0.10.0'} - dev: true /del@7.0.0: resolution: {integrity: sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q==} @@ -1331,34 +1089,34 @@ packages: ansi-colors: 4.1.3 dev: true - /esbuild@0.16.17: - resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} + /esbuild@0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.16.17 - '@esbuild/android-arm64': 0.16.17 - '@esbuild/android-x64': 0.16.17 - '@esbuild/darwin-arm64': 0.16.17 - '@esbuild/darwin-x64': 0.16.17 - '@esbuild/freebsd-arm64': 0.16.17 - '@esbuild/freebsd-x64': 0.16.17 - '@esbuild/linux-arm': 0.16.17 - '@esbuild/linux-arm64': 0.16.17 - '@esbuild/linux-ia32': 0.16.17 - '@esbuild/linux-loong64': 0.16.17 - '@esbuild/linux-mips64el': 0.16.17 - '@esbuild/linux-ppc64': 0.16.17 - '@esbuild/linux-riscv64': 0.16.17 - '@esbuild/linux-s390x': 0.16.17 - '@esbuild/linux-x64': 0.16.17 - '@esbuild/netbsd-x64': 0.16.17 - '@esbuild/openbsd-x64': 0.16.17 - '@esbuild/sunos-x64': 0.16.17 - '@esbuild/win32-arm64': 0.16.17 - '@esbuild/win32-ia32': 0.16.17 - '@esbuild/win32-x64': 0.16.17 + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 dev: true /escalade@3.1.1: @@ -1387,10 +1145,6 @@ packages: hasBin: true dev: true - /estree-walker@2.0.2: - resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: true - /esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} @@ -1538,7 +1292,7 @@ packages: debug: optional: true dependencies: - debug: 4.3.4(supports-color@9.3.1) + debug: 4.3.4(supports-color@8.1.1) /forever-agent@0.6.1: resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==} @@ -1582,15 +1336,6 @@ packages: universalify: 2.0.0 dev: true - /fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - dependencies: - graceful-fs: 4.2.10 - jsonfile: 4.0.0 - universalify: 0.1.2 - dev: true - /fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -1689,20 +1434,6 @@ packages: ini: 2.0.0 dev: true - /globby@10.0.1: - resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} - engines: {node: '>=8'} - dependencies: - '@types/glob': 7.2.0 - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.2.11 - glob: 7.2.3 - ignore: 5.2.0 - merge2: 1.4.1 - slash: 3.0.0 - dev: true - /globby@13.1.3: resolution: {integrity: sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1720,7 +1451,6 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true /has-proto@1.0.1: resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} @@ -1818,13 +1548,6 @@ packages: binary-extensions: 2.2.0 dev: true - /is-builtin-module@3.2.1: - resolution: {integrity: sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==} - engines: {node: '>=6'} - dependencies: - builtin-modules: 3.3.0 - dev: true - /is-ci@3.0.1: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true @@ -1872,10 +1595,6 @@ packages: is-path-inside: 3.0.3 dev: true - /is-module@1.0.0: - resolution: {integrity: sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==} - dev: true - /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -1896,11 +1615,6 @@ packages: engines: {node: '>=12'} dev: true - /is-plain-object@3.0.1: - resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} - engines: {node: '>=0.10.0'} - dev: true - /is-plain-object@5.0.0: resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} engines: {node: '>=0.10.0'} @@ -1910,12 +1624,6 @@ packages: resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} dev: true - /is-reference@1.2.1: - resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} - dependencies: - '@types/estree': 1.0.0 - dev: true - /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} @@ -1943,29 +1651,21 @@ packages: resolution: {integrity: sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==} dev: true - /itk-image-io@1.0.0-b.146: - resolution: {integrity: sha512-OBf1QDYcaq9Xzyc7O8jfeohjsz85+5Xj8ygTQhP4lNnuP9ndG6pgf50YFUPqFWoK3Rw0iINbnsqtIL29UhI4xA==} - dependencies: - itk-wasm: 1.0.0-b.146 - transitivePeerDependencies: - - debug - dev: true - - /itk-wasm@1.0.0-b.146: - resolution: {integrity: sha512-1opxFHG1Xspu/gFVbmYfhEy6H1/PDs+AsaZ95ZdU7DL9Xul9tsstFcXwsblB8JXNEXqcPG2h61gAq7BYF4UhdQ==} + /itk-wasm@1.0.0-b.154: + resolution: {integrity: sha512-bzwOpA4kaNNC2SUTk2wWfHdg+4G6kW8KdMcp3kChhKWzR3T76bV9yybDsuoYq/6aWFQtIgEJLMFcTUpwk0PodA==} hasBin: true dependencies: '@babel/runtime': 7.19.0 - '@thewtex/zstddec': 0.1.2 + '@thewtex/zstddec': 0.2.0 '@types/emscripten': 1.39.6 axios: 1.4.0 + comlink: 4.4.1 commander: 9.4.0 fs-extra: 10.1.0 glob: 8.1.0 markdown-table: 3.0.3 mime-types: 2.1.35 wasm-feature-detect: 1.5.1 - webworker-promise: 0.4.4 transitivePeerDependencies: - debug @@ -2004,12 +1704,6 @@ packages: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} dev: true - /jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - optionalDependencies: - graceful-fs: 4.2.10 - dev: true - /jsonfile@6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -2119,13 +1813,6 @@ packages: yallist: 4.0.0 dev: true - /magic-string@0.27.0: - resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - /map-age-cleaner@0.1.3: resolution: {integrity: sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==} engines: {node: '>=6'} @@ -2453,12 +2140,6 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true - /randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - dependencies: - safe-buffer: 5.2.1 - dev: true - /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -2536,32 +2217,8 @@ packages: glob: 7.2.3 dev: true - /rollup-plugin-copy@3.4.0: - resolution: {integrity: sha512-rGUmYYsYsceRJRqLVlE9FivJMxJ7X6jDlP79fmFkL8sJs7VVMSVyA2yfyL+PGyO/vJs4A87hwhgVfz61njI+uQ==} - engines: {node: '>=8.3'} - dependencies: - '@types/fs-extra': 8.1.2 - colorette: 1.4.0 - fs-extra: 8.1.0 - globby: 10.0.1 - is-plain-object: 3.0.1 - dev: true - - /rollup-plugin-ignore@1.0.10: - resolution: {integrity: sha512-VsbnfwwaTv2Dxl2onubetX/3RnSnplNnjdix0hvF8y2YpqdzlZrjIq6zkcuVJ08XysS8zqW3gt3ORBndFDgsrg==} - dev: true - - /rollup-plugin-polyfill-node@0.12.0(rollup@3.18.0): - resolution: {integrity: sha512-PWEVfDxLEKt8JX1nZ0NkUAgXpkZMTb85rO/Ru9AQ69wYW8VUCfDgP4CGRXXWYni5wDF0vIeR1UoF3Jmw/Lt3Ug==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 || ^3.0.0 - dependencies: - '@rollup/plugin-inject': 5.0.3(rollup@3.18.0) - rollup: 3.18.0 - dev: true - - /rollup@3.18.0: - resolution: {integrity: sha512-J8C6VfEBjkvYPESMQYxKHxNOh4A5a3FlP+0BETGo34HEcE4eTlgCrO2+eWzlu2a/sHs2QUkZco+wscH7jhhgWg==} + /rollup@3.29.4: + resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: @@ -2611,12 +2268,6 @@ packages: type-fest: 0.13.1 dev: true - /serialize-javascript@6.0.1: - resolution: {integrity: sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==} - dependencies: - randombytes: 2.1.0 - dev: true - /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2696,27 +2347,11 @@ packages: is-fullwidth-code-point: 4.0.0 dev: true - /smob@1.4.0: - resolution: {integrity: sha512-MqR3fVulhjWuRNSMydnTlweu38UhQ0HXM4buStD/S3mc/BzX3CuM9OmhyQpmtYCvoYdl5ris6TI0ZqH355Ymqg==} - dev: true - /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} dev: true - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - dev: true - - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true - /split@0.3.3: resolution: {integrity: sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==} dependencies: @@ -2750,7 +2385,7 @@ packages: escape-string-regexp: 2.0.0 dev: true - /start-server-and-test@2.0.0(supports-color@9.3.1): + /start-server-and-test@2.0.0: resolution: {integrity: sha512-UqKLw0mJbfrsG1jcRLTUlvuRi9sjNuUiDOLI42r7R5fA9dsFoywAy9DoLXNYys9B886E4RCKb+qM1Gzu96h7DQ==} engines: {node: '>=6'} hasBin: true @@ -2758,7 +2393,7 @@ packages: arg: 5.0.2 bluebird: 3.7.2 check-more-types: 2.24.0 - debug: 4.3.4(supports-color@9.3.1) + debug: 4.3.4(supports-color@8.1.1) execa: 5.1.1 lazy-ass: 1.6.0 ps-tree: 1.2.0 @@ -2832,11 +2467,6 @@ packages: engines: {node: '>=10'} dependencies: has-flag: 4.0.0 - dev: true - - /supports-color@9.3.1: - resolution: {integrity: sha512-knBY82pjmnIzK3NifMo3RxEIRD9E0kIzV4BKcyTZ9+9kWgLMxd4PrsTSMoFQUabgRBbF8KOLRDCyKgNV+iK44Q==} - engines: {node: '>=12'} /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -2848,17 +2478,6 @@ packages: engines: {node: '>=14.16'} dev: true - /terser@5.19.2: - resolution: {integrity: sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==} - engines: {node: '>=10'} - hasBin: true - dependencies: - '@jridgewell/source-map': 0.3.5 - acorn: 8.8.2 - commander: 2.20.3 - source-map-support: 0.5.21 - dev: true - /throttleit@1.0.0: resolution: {integrity: sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g==} dev: true @@ -2926,11 +2545,6 @@ packages: hasBin: true dev: true - /universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - dev: true - /universalify@0.2.0: resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==} engines: {node: '>= 4.0.0'} @@ -2966,8 +2580,8 @@ packages: extsprintf: 1.3.0 dev: true - /vite-plugin-static-copy@0.14.0(vite@4.1.5): - resolution: {integrity: sha512-RMFmb4czomcrsbQBiUZs9HcDGN3kxGvF+OrtkfTVocp12CuoUCuJQhcY26RK35A6KS4WasGzEwcYZqHMjkAvVw==} + /vite-plugin-static-copy@0.17.0(vite@4.5.0): + resolution: {integrity: sha512-2HpNbHfDt8SDy393AGXh9llHkc8FJMQkI8s3T5WsH3SWLMO+f5cFIyPErl4yGKU9Uh3Vaqsd4lHZYTf042fQ2A==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: vite: ^3.0.0 || ^4.0.0 @@ -2976,16 +2590,17 @@ packages: fast-glob: 3.2.11 fs-extra: 11.1.0 picocolors: 1.0.0 - vite: 4.1.5(@types/node@20.4.8) + vite: 4.5.0(@types/node@20.4.8) dev: true - /vite@4.1.5(@types/node@20.4.8): - resolution: {integrity: sha512-zJ0RiVkf61kpd7O+VtU6r766xgnTaIknP/lR6sJTZq3HtVJ3HGnTo5DaJhTUtYoTyS/CQwZ6yEVdc/lrmQT7dQ==} + /vite@4.5.0(@types/node@20.4.8): + resolution: {integrity: sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: '@types/node': '>= 14' less: '*' + lightningcss: ^1.21.0 sass: '*' stylus: '*' sugarss: '*' @@ -2995,6 +2610,8 @@ packages: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true stylus: @@ -3005,10 +2622,9 @@ packages: optional: true dependencies: '@types/node': 20.4.8 - esbuild: 0.16.17 + esbuild: 0.18.20 postcss: 8.4.31 - resolve: 1.22.1 - rollup: 3.18.0 + rollup: 3.29.4 optionalDependencies: fsevents: 2.3.2 dev: true @@ -3030,9 +2646,6 @@ packages: /wasm-feature-detect@1.5.1: resolution: {integrity: sha512-GHr23qmuehNXHY4902/hJ6EV5sUANIJC3R/yMfQ7hWDg3nfhlcJfnIL96R2ohpIwa62araN6aN4bLzzzq5GXkg==} - /webworker-promise@0.4.4: - resolution: {integrity: sha512-NfdSlaWqd+0iSrQudB0N0MELfJ9TVTlynhXMpi06piuZhyc9Yy7Hz6BFu2HUkvIb9lCS0pFW42ptd/JnXVnptg==} - /well-known-symbols@2.0.0: resolution: {integrity: sha512-ZMjC3ho+KXo0BfJb7JgtQ5IBuvnShdlACNkKkdsqBmYw3bPAaJfPeYUo6tLUaT5tG/Gkh7xkpBhKRQ9e7pyg9Q==} engines: {node: '>=6'} diff --git a/packages/dicom/typescript/src/index-worker-embedded.min.ts b/packages/dicom/typescript/src/index-worker-embedded.min.ts new file mode 100644 index 000000000..737584dee --- /dev/null +++ b/packages/dicom/typescript/src/index-worker-embedded.min.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.min.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' diff --git a/packages/dicom/typescript/src/index-worker-embedded.ts b/packages/dicom/typescript/src/index-worker-embedded.ts new file mode 100644 index 000000000..cdbc5d63d --- /dev/null +++ b/packages/dicom/typescript/src/index-worker-embedded.ts @@ -0,0 +1,9 @@ +// Generated file. To retain edits, remove this comment. + +// Generated file. To retain edits, remove this comment. + +import { setPipelineWorkerUrl } from './index.js' +import pipelineWorker from '../node_modules/itk-wasm/dist/core/web-workers/bundles/itk-wasm-pipeline.worker.js' +setPipelineWorkerUrl(pipelineWorker) + +export * from './index.js' \ No newline at end of file diff --git a/packages/dicom/typescript/src/package.json b/packages/dicom/typescript/src/package.json new file mode 120000 index 000000000..4e26811d4 --- /dev/null +++ b/packages/dicom/typescript/src/package.json @@ -0,0 +1 @@ +../package.json \ No newline at end of file diff --git a/packages/dicom/typescript/src/pipeline-worker-url.ts b/packages/dicom/typescript/src/pipeline-worker-url.ts index 688fb1045..39118ba4a 100644 --- a/packages/dicom/typescript/src/pipeline-worker-url.ts +++ b/packages/dicom/typescript/src/pipeline-worker-url.ts @@ -1,8 +1,8 @@ import { getPipelineWorkerUrl as itkWasmGetPipelineWorkerUrl } from 'itk-wasm' -import packageJson from '../package.json' let pipelineWorkerUrl: string | URL | null | undefined -const defaultPipelineWorkerUrl = `https://cdn.jsdelivr.net/npm/@itk-wasm/dicom@${packageJson.version}/dist/web-workers/pipeline.worker.js` +// Use the version shipped with an app's bundler +const defaultPipelineWorkerUrl = null export function setPipelineWorkerUrl (workerUrl: string | URL | null): void { pipelineWorkerUrl = workerUrl diff --git a/packages/dicom/typescript/src/pipelines-base-url.ts b/packages/dicom/typescript/src/pipelines-base-url.ts index e33d48718..f66a0c81c 100644 --- a/packages/dicom/typescript/src/pipelines-base-url.ts +++ b/packages/dicom/typescript/src/pipelines-base-url.ts @@ -1,5 +1,5 @@ import { getPipelinesBaseUrl as itkWasmGetPipelinesBaseUrl } from 'itk-wasm' -import packageJson from '../package.json' +import packageJson from './package.json' assert { type: 'json' } let pipelinesBaseUrl: string | URL | undefined let defaultPipelinesBaseUrl: string | URL = `https://cdn.jsdelivr.net/npm/@itk-wasm/dicom@${packageJson.version}/dist/pipelines` diff --git a/packages/dicom/typescript/src/read-dicom-tags-node.ts b/packages/dicom/typescript/src/read-dicom-tags-node.ts index ba9ff58e1..47cce5720 100644 --- a/packages/dicom/typescript/src/read-dicom-tags-node.ts +++ b/packages/dicom/typescript/src/read-dicom-tags-node.ts @@ -53,7 +53,7 @@ async function readDicomTagsNode( } - const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), '..', 'pipelines', 'read-dicom-tags') + const pipelinePath = path.join(path.dirname(import.meta.url.substring(7)), 'pipelines', 'read-dicom-tags') const { returnValue, diff --git a/packages/dicom/typescript/test/browser/demo-app/read-dicom-encapsulated-pdf-controller.ts b/packages/dicom/typescript/test/browser/demo-app/read-dicom-encapsulated-pdf-controller.ts index 198f2599f..62a049d59 100644 --- a/packages/dicom/typescript/test/browser/demo-app/read-dicom-encapsulated-pdf-controller.ts +++ b/packages/dicom/typescript/test/browser/demo-app/read-dicom-encapsulated-pdf-controller.ts @@ -1,4 +1,4 @@ -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' import readDicomEncapsulatedPdfLoadSampleInputs, { usePreRun } from "./read-dicom-encapsulated-pdf-load-sample-inputs.js" class ReadDicomEncapsulatedPdfModel { diff --git a/packages/dicom/typescript/test/browser/demo-app/read-image-dicom-file-series-controller.ts b/packages/dicom/typescript/test/browser/demo-app/read-image-dicom-file-series-controller.ts index 80fa34061..1e1be0e28 100644 --- a/packages/dicom/typescript/test/browser/demo-app/read-image-dicom-file-series-controller.ts +++ b/packages/dicom/typescript/test/browser/demo-app/read-image-dicom-file-series-controller.ts @@ -1,5 +1,5 @@ import { writeImageArrayBuffer, copyImage } from 'itk-wasm' -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' import readImageDicomFileSeriesLoadSampleInputs, { usePreRun } from "./read-image-dicom-file-series-load-sample-inputs.js" class ReadImageDicomFileSeriesModel { diff --git a/packages/dicom/typescript/test/browser/demo-app/structured-report-to-html-controller.ts b/packages/dicom/typescript/test/browser/demo-app/structured-report-to-html-controller.ts index 8653231b2..250f629cc 100644 --- a/packages/dicom/typescript/test/browser/demo-app/structured-report-to-html-controller.ts +++ b/packages/dicom/typescript/test/browser/demo-app/structured-report-to-html-controller.ts @@ -1,4 +1,4 @@ -import * as dicom from '../../../dist/bundles/dicom.js' +import * as dicom from '../../../dist/index.js' import structuredReportToHtmlLoadSampleInputs, { usePreRun } from "./structured-report-to-html-load-sample-inputs.js" class StructuredReportToHtmlModel { diff --git a/packages/dicom/typescript/test/node/dcmtk.js b/packages/dicom/typescript/test/node/dcmtk.js index 9ad4a441c..ab035cd1b 100644 --- a/packages/dicom/typescript/test/node/dcmtk.js +++ b/packages/dicom/typescript/test/node/dcmtk.js @@ -6,8 +6,8 @@ import { structuredReportToHtmlNode , readDicomEncapsulatedPdfNode, applyPresentationStateToImageNode, -} from '../../dist/bundles/dicom-node.js' -import { readImageLocalFile } from 'itk-wasm' +} from '../../dist/index-node.js' +import { readImageNode } from '@itk-wasm/image-io' function arrayEquals(a, b) { return (a.length === b.length && a.every((val, idx) => val === b[idx])) @@ -189,7 +189,7 @@ test('Apply color presentation state (CSPS) to a color dicom image.', async t => const baselineImage = 'csps-output-image-baseline.bmp' const baselineImageFilePath = baselinePathPrefix + baselineImage - const baselinePixels = await readImageLocalFile(baselineImageFilePath) + const baselinePixels = await readImageNode(baselineImageFilePath) t.assert(baselinePixels.data.length === outputImage.data.length) t.assert(Buffer.compare(baselinePixels.data, outputImage.data) === 0) }) diff --git a/packages/dicom/typescript/test/node/gdcm.js b/packages/dicom/typescript/test/node/gdcm.js index 3e2a7e3cd..bb1771f7b 100644 --- a/packages/dicom/typescript/test/node/gdcm.js +++ b/packages/dicom/typescript/test/node/gdcm.js @@ -4,7 +4,7 @@ import glob from 'glob' import fs from 'fs-extra' import { IntTypes, PixelTypes, getMatrixElement } from 'itk-wasm' -import { readImageDicomFileSeriesNode, readDicomTagsNode } from '../../dist/bundles/dicom-node.js' +import { readImageDicomFileSeriesNode, readDicomTagsNode } from '../../dist/index-node.js' const testDataInputDirectory = path.resolve('..', 'test', 'data', 'input') const testSeriesDirectory = path.resolve(testDataInputDirectory, 'DicomImageOrientationTest') diff --git a/packages/dicom/typescript/tsconfig.json b/packages/dicom/typescript/tsconfig.json index 4eba4b8ec..242f02a0c 100644 --- a/packages/dicom/typescript/tsconfig.json +++ b/packages/dicom/typescript/tsconfig.json @@ -16,8 +16,10 @@ "noImplicitReturns": true, "skipLibCheck": true, "declaration": true, - "emitDeclarationOnly": true, - "declarationDir": "dist/" + "emitDeclarationOnly": false, + "outDir": "dist/", + "rootDir": "src/" }, - "include": ["src/*.ts"] + "include": ["src/*.ts"], + "exclude": ["src/index-worker-embedded*.ts"] } From 884a48c77de998f5910e8b98fdda66a2e35f1f54 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 8 Nov 2023 23:27:04 -0500 Subject: [PATCH 22/23] build(image-io): bump typescript for itk-wasm 1.0.0-b.154 --- .gitignore | 1 + package.json | 18 +++++++++--------- .../itkwasm_image_io_emscripten/_version.py | 2 +- .../itkwasm_image_io_emscripten/js_package.py | 2 +- .../itkwasm-image-io-emscripten/pyproject.toml | 1 + .../test/fixtures.py | 1 - .../itkwasm_image_io_wasi/_version.py | 2 +- .../itkwasm_image_io/_version.py | 2 +- packages/image-io/typescript/package.json | 2 +- 9 files changed, 16 insertions(+), 15 deletions(-) diff --git a/.gitignore b/.gitignore index 9d15384a1..c061c962f 100644 --- a/.gitignore +++ b/.gitignore @@ -81,6 +81,7 @@ test/pipelines/bindgen-interface-types-pipeline/python-web-demo/ packages/image-io/test/ packages/image-io/typescript/demo-app-rollup/ +packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/wasm_modules/ cypress/screenshots/ cypress/videos/ diff --git a/package.json b/package.json index 3f035fa9f..580e63184 100644 --- a/package.json +++ b/package.json @@ -38,18 +38,18 @@ "build:webpack": "webpack --mode production --progress --color && webpack --mode development --progress --color", "build:emscripten": "node ./src/build-emscripten.js", "build:emscripten:compress-stringify": "node ./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build build ", - "build:bindgen:typescript:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --package-version 1.0.0 --package-name @itk-wasm/compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b wasi-build bindgen --interface python --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 1.0.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python-web-demo:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --interface python-web-demo --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 1.0.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --package-version 2.0.1 --package-name @itk-wasm/compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b wasi-build bindgen --interface python --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 2.0.1 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python-web-demo:compress-stringify": "./src/itk-wasm-cli.js -s packages/compress-stringify -b emscripten-build bindgen --interface python-web-demo --package-name itkwasm-compress-stringify --package-description \"Zstandard compression and decompression and base64 encoding and decoding in WebAssembly.\" --package-version 2.0.1 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:dicom": "node ./src/itk-wasm-cli.js -s packages/dicom -b emscripten-build build", - "build:bindgen:typescript:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b emscripten-build bindgen --package-version 4.0.0 --package-name @itk-wasm/dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b wasi-build bindgen --package-version 4.0.0 --interface python --package-name itkwasm-dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b emscripten-build bindgen --package-version 5.0.0 --package-name @itk-wasm/dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:dicom": "./src/itk-wasm-cli.js -s packages/dicom -b wasi-build bindgen --package-version 5.0.0 --interface python --package-name itkwasm-dicom --package-description \"Read files and images related to DICOM file format.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:compare-images": "node ./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build build", - "build:bindgen:typescript:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build bindgen --package-version 3.0.1 --package-name @itk-wasm/compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b wasi-build bindgen --package-version 3.0.1 --interface python --package-name itkwasm-compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b emscripten-build bindgen --package-version 4.0.0 --package-name @itk-wasm/compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:compare-images": "./src/itk-wasm-cli.js -s packages/compare-images -b wasi-build bindgen --package-version 4.0.0 --interface python --package-name itkwasm-compare-images --package-description \"Compare images with a tolerance for regression testing.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:image-io": "node ./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build build", - "build:bindgen:typescript:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build bindgen --package-version 0.4.0 --package-name @itk-wasm/image-io --package-description \"Input and output for scientific and medical image file formats.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", - "build:bindgen:python:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b wasi-build bindgen --interface python --package-name itkwasm-image-io --package-description \"Input and output for scientific and medical image file formats.\" --package-version 0.4.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:typescript:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b emscripten-build bindgen --package-version 0.5.0 --package-name @itk-wasm/image-io --package-description \"Input and output for scientific and medical image file formats.\" --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", + "build:bindgen:python:image-io": "./src/itk-wasm-cli.js -s packages/image-io -b wasi-build bindgen --interface python --package-name itkwasm-image-io --package-description \"Input and output for scientific and medical image file formats.\" --package-version 0.5.0 --repository 'https://github.com/InsightSoftwareConsortium/itk-wasm'", "build:emscripten:packages": "npm run build:emscripten:compress-stringify && npm run build:bindgen:typescript:compress-stringify && npm run build:emscripten:dicom && npm run build:bindgen:typescript:dicom && npm run build:emscripten:compare-images && npm run build:bindgen:typescript:compare-images && npm run build:emscripten:image-io && npm run build:bindgen:typescript:image-io", "build:wasi": "node ./src/build-wasi.js && npm run build:wasi:packages", "build:wasi:compress-stringify": "node ./src/itk-wasm-cli.js -i itkwasm/wasi:latest -s packages/compress-stringify -b wasi-build build", diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py index 6a9beea82..3d187266f 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/_version.py @@ -1 +1 @@ -__version__ = "0.4.0" +__version__ = "0.5.0" diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py index e9133f954..1d4eab40f 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py +++ b/packages/image-io/python/itkwasm-image-io-emscripten/itkwasm_image_io_emscripten/js_package.py @@ -3,6 +3,6 @@ from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__ -default_js_module = """data:text/javascript;base64,dmFyIGZyPSIxLjAuMC1iLjE1NCIscmU9ZnI7dmFyIGNyPXtwaXBlbGluZVdvcmtlclVybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstd2FzbUAke3JlfS9kaXN0L2NvcmUvd2ViLXdvcmtlcnMvYnVuZGxlcy9waXBlbGluZS5taW4ud29ya2VyLmpzYCxpbWFnZUlPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1pbWFnZS1pb0Ake3JlfWAsbWVzaElPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1tZXNoLWlvQCR7cmV9YCxwaXBlbGluZXNVcmw6YGh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vaXRrLXdhc21AJHtyZX0vZGlzdC9waXBlbGluZXNgfSx2PWNyO3ZhciBkcj17VGV4dEZpbGU6IkludGVyZmFjZVRleHRGaWxlIixCaW5hcnlGaWxlOiJJbnRlcmZhY2VCaW5hcnlGaWxlIixUZXh0U3RyZWFtOiJJbnRlcmZhY2VUZXh0U3RyZWFtIixCaW5hcnlTdHJlYW06IkludGVyZmFjZUJpbmFyeVN0cmVhbSIsSW1hZ2U6IkludGVyZmFjZUltYWdlIixNZXNoOiJJbnRlcmZhY2VNZXNoIixQb2x5RGF0YToiSW50ZXJmYWNlUG9seURhdGEiLEpzb25Db21wYXRpYmxlOiJJbnRlcmZhY2VKc29uQ29tcGF0aWJsZSJ9LG09ZHI7dmFyIEJyPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0sUT1Ccjt2YXIgQ3I9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFM9Q3I7dmFyIHlyPXtUZXh0OiJUZXh0IixCaW5hcnk6IkJpbmFyeSIsSW1hZ2U6IkltYWdlIixNZXNoOiJNZXNoIn0sVz15cjt2YXIgRXI9e1Vua25vd246IlVua25vd24iLFNjYWxhcjoiU2NhbGFyIixSR0I6IlJHQiIsUkdCQToiUkdCQSIsT2Zmc2V0OiJPZmZzZXQiLFZlY3RvcjoiVmVjdG9yIixQb2ludDoiUG9pbnQiLENvdmFyaWFudFZlY3RvcjoiQ292YXJpYW50VmVjdG9yIixTeW1tZXRyaWNTZWNvbmRSYW5rVGVuc29yOiJTeW1tZXRyaWNTZWNvbmRSYW5rVGVuc29yIixEaWZmdXNpb25UZW5zb3IzRDoiRGlmZnVzaW9uVGVuc29yM0QiLENvbXBsZXg6IkNvbXBsZXgiLEZpeGVkQXJyYXk6IkZpeGVkQXJyYXkiLEFycmF5OiJBcnJheSIsTWF0cml4OiJNYXRyaXgiLFZhcmlhYmxlTGVuZ3RoVmVjdG9yOiJWYXJpYWJsZUxlbmd0aFZlY3RvciIsVmFyaWFibGVTaXplTWF0cml4OiJWYXJpYWJsZVNpemVNYXRyaXgifSx1ZT1FcjtmdW5jdGlvbiBRcihlLEEsdCxyLGEpe2Vbcit0KkFdPWF9dmFyIHN0PVFyO3ZhciBOZT1jbGFzc3tjb25zdHJ1Y3RvcihBPTIsdD1RLlVJbnQ4LHI9dWUuU2NhbGFyLGE9MSl7dGhpcy5kaW1lbnNpb249QSx0aGlzLmNvbXBvbmVudFR5cGU9dCx0aGlzLnBpeGVsVHlwZT1yLHRoaXMuY29tcG9uZW50cz1hfX0sSXQ9TmU7dmFyIFBlPWNsYXNze2NvbnN0cnVjdG9yKEE9bmV3IEl0KXt0aGlzLmltYWdlVHlwZT1BLHRoaXMubmFtZT0iaW1hZ2UiO2xldCB0PUEuZGltZW5zaW9uO3RoaXMub3JpZ2luPW5ldyBBcnJheSh0KSx0aGlzLm9yaWdpbi5maWxsKDApLHRoaXMuc3BhY2luZz1uZXcgQXJyYXkodCksdGhpcy5zcGFjaW5nLmZpbGwoMSksdGhpcy5kaXJlY3Rpb249bmV3IEZsb2F0NjRBcnJheSh0KnQpLHRoaXMuZGlyZWN0aW9uLmZpbGwoMCk7Zm9yKGxldCByPTA7cjx0O3IrKylzdCh0aGlzLmRpcmVjdGlvbix0LHIsciwxKTt0aGlzLnNpemU9bmV3IEFycmF5KHQpLHRoaXMuc2l6ZS5maWxsKDApLHRoaXMubWV0YWRhdGE9bmV3IE1hcCx0aGlzLmRhdGE9bnVsbH19LEs9UGU7ZnVuY3Rpb24gaHIoZSxBKXtsZXQgdD1udWxsO3N3aXRjaChlKXtjYXNlIFEuVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDg6e3Q9bmV3IEludDhBcnJheShBKTticmVha31jYXNlIFEuVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShBKTticmVha31jYXNlIFEuSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KEEpO2JyZWFrfWNhc2UgUS5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KEEpOnQ9bmV3IFVpbnQ4QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoQSk6dD1uZXcgVWludDhBcnJheShBKTticmVha31jYXNlIFMuRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KEEpO2JyZWFrfWNhc2UgUy5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoQSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIEQ9aHI7ZnVuY3Rpb24gd3IoZSl7bGV0IEE9bmV3IEsoZS5pbWFnZVR5cGUpO2lmKEEubmFtZT1lLm5hbWUsQS5vcmlnaW49QXJyYXkuZnJvbShlLm9yaWdpbiksQS5zcGFjaW5nPUFycmF5LmZyb20oZS5zcGFjaW5nKSxBLmRpcmVjdGlvbj1lLmRpcmVjdGlvbi5zbGljZSgpLEEuc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSksZS5kYXRhIT09bnVsbCl7bGV0IHQ9ZS5kYXRhLmNvbnN0cnVjdG9yO0EuZGF0YT1uZXcgdChlLmRhdGEubGVuZ3RoKSxBLmRhdGEhPW51bGwmJkEuZGF0YS5zZXQoZS5kYXRhLDApfXJldHVybiBBfXZhciB4ZT13cjtmdW5jdGlvbiBScihlKXtpZihlLmxlbmd0aDwxKXRocm93IEVycm9yKCJBdCBsZWFzdCBvbmUgaW1hZ2VzIGlzIHJlcXVpcmVkLiIpO2xldCBBPWVbMF07aWYoQS5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiSW1hZ2UgZGF0YSBpcyBudWxsLiIpO2xldCB0PW5ldyBLKEEuaW1hZ2VUeXBlKTt0Lm9yaWdpbj1BcnJheS5mcm9tKEEub3JpZ2luKSx0LnNwYWNpbmc9QXJyYXkuZnJvbShBLnNwYWNpbmcpO2xldCByPXQuaW1hZ2VUeXBlLmRpbWVuc2lvbjt0LmRpcmVjdGlvbj1BLmRpcmVjdGlvbi5zbGljZSgpO2xldCBhPXItMTt0LnNpemU9QXJyYXkuZnJvbShBLnNpemUpO2xldCBvPWUucmVkdWNlKChuLHUpPT5uK3Uuc2l6ZVthXSwwKTt0LnNpemVbYV09bztsZXQgaT10LnNpemUucmVkdWNlKChuLHUpPT5uKnUsMSkqdC5pbWFnZVR5cGUuY29tcG9uZW50cyxsPUEuZGF0YS5jb25zdHJ1Y3Rvcjt0LmRhdGE9bmV3IGwoaSk7bGV0IGY9dC5pbWFnZVR5cGUuY29tcG9uZW50cztmb3IobGV0IG49MDtuPHQuc2l6ZS5sZW5ndGgtMTtuKyspZio9dC5zaXplW25dO2xldCBnPTA7aWYodC5kYXRhIT1udWxsKWZvcihsZXQgbj0wO248ZS5sZW5ndGg7bisrKXQuZGF0YS5zZXQoZVtuXS5kYXRhLGYqZyksZys9ZVtuXS5zaXplW2FdO2Vsc2UgdGhyb3cgRXJyb3IoIkNvdWxkIG5vdCBjcmVhdGUgcmVzdWx0IGltYWdlIGRhdGEuIik7cmV0dXJuIHR9dmFyIEdlPVJyO2Z1bmN0aW9uIGJyKGUsQSl7bGV0IHQ9T2JqZWN0LmFzc2lnbih7fSxlLmltYWdlVHlwZSk7aWYodHlwZW9mIEE8InUiJiZ0eXBlb2YgQS5waXhlbFR5cGU8InUiJiYodC5waXhlbFR5cGU9QS5waXhlbFR5cGUsQS5waXhlbFR5cGU9PT11ZS5TY2FsYXImJnQuY29tcG9uZW50cyE9PTEpKXRocm93IG5ldyBFcnJvcigiQ2Fubm90IGNhc3QgbXVsdGktY29tcG9uZW50IGltYWdlIHRvIGEgc2NhbGFyIGltYWdlIik7dHlwZW9mIEE8InUiJiZ0eXBlb2YgQS5jb21wb25lbnRUeXBlPCJ1IiYmQS5jb21wb25lbnRUeXBlIT09ZS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSYmKHQuY29tcG9uZW50VHlwZT1BLmNvbXBvbmVudFR5cGUpO2xldCByPW5ldyBLKHQpO2lmKHIubmFtZT1lLm5hbWUsci5vcmlnaW49QXJyYXkuZnJvbShlLm9yaWdpbiksci5zcGFjaW5nPUFycmF5LmZyb20oZS5zcGFjaW5nKSxyLmRpcmVjdGlvbj1lLmRpcmVjdGlvbi5zbGljZSgpLHIuc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSksci5tZXRhZGF0YT1uZXcgTWFwKEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShlLm1ldGFkYXRhKSkpKSxlLmRhdGEhPT1udWxsKWlmKHR5cGVvZiBBPCJ1IiYmdHlwZW9mIEEuY29tcG9uZW50VHlwZTwidSImJkEuY29tcG9uZW50VHlwZSE9PWUuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpc3dpdGNoKGUuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpe2Nhc2UgUS5VSW50ODpjYXNlIFEuSW50ODpjYXNlIFEuVUludDE2OmNhc2UgUS5JbnQxNjpjYXNlIFEuVUludDMyOmNhc2UgUS5JbnQzMjpjYXNlIFMuRmxvYXQzMjpjYXNlIFMuRmxvYXQ2NDpzd2l0Y2goci5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSl7Y2FzZSBRLlVJbnQ4OnIuZGF0YT1uZXcgVWludDhBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQ4OnIuZGF0YT1uZXcgSW50OEFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQxNjpyLmRhdGE9bmV3IFVpbnQxNkFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLkludDE2OnIuZGF0YT1uZXcgSW50MTZBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5VSW50MzI6ci5kYXRhPW5ldyBVaW50MzJBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQzMjpyLmRhdGE9bmV3IEludDMyQXJyYXkoZS5kYXRhKTticmVhaztjYXNlIFMuRmxvYXQzMjpyLmRhdGE9bmV3IEZsb2F0MzJBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUy5GbG9hdDY0OnIuZGF0YT1uZXcgRmxvYXQ2NEFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQ2NDpyLmRhdGE9bmV3IEJpZ1VpbnQ2NEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPUJpZ0ludC5hc0ludE4oNjQsQmlnSW50KGUuZGF0YVthXSkpO2JyZWFrO2Nhc2UgUS5JbnQ2NDpyLmRhdGE9bmV3IEJpZ0ludDY0QXJyYXkoZS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBhPTA7YTxyLmRhdGEubGVuZ3RoO2ErKylyLmRhdGFbYV09QmlnSW50LmFzVWludE4oNjQsQmlnSW50KGUuZGF0YVthXSkpO2JyZWFrfWJyZWFrO2Nhc2UgUS5VSW50NjQ6Y2FzZSBRLkludDY0OnN3aXRjaChyLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKXtjYXNlIFEuVUludDg6ci5kYXRhPW5ldyBVaW50OEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5JbnQ4OnIuZGF0YT1uZXcgSW50OEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50MTY6ci5kYXRhPW5ldyBVaW50MTZBcnJheShlLmRhdGEubGVuZ3RoKTtmb3IobGV0IGE9MDthPHIuZGF0YS5sZW5ndGg7YSsrKXIuZGF0YVthXT1OdW1iZXIoZS5kYXRhW2FdKTticmVhaztjYXNlIFEuSW50MTY6ci5kYXRhPW5ldyBJbnQxNkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50MzI6ci5kYXRhPW5ldyBVaW50MzJBcnJheShlLmRhdGEubGVuZ3RoKTtmb3IobGV0IGE9MDthPHIuZGF0YS5sZW5ndGg7YSsrKXIuZGF0YVthXT1OdW1iZXIoZS5kYXRhW2FdKTticmVhaztjYXNlIFEuSW50MzI6ci5kYXRhPW5ldyBJbnQzMkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUy5GbG9hdDMyOnIuZGF0YT1uZXcgRmxvYXQzMkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUy5GbG9hdDY0OnIuZGF0YT1uZXcgRmxvYXQ2NEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50NjQ6ci5kYXRhPW5ldyBCaWdVaW50NjRBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQ2NDpyLmRhdGE9bmV3IEJpZ0ludDY0QXJyYXkoZS5kYXRhKTticmVha31icmVha31lbHNle2xldCBhPWUuZGF0YS5jb25zdHJ1Y3RvcjtyLmRhdGE9bmV3IGEoZS5kYXRhLmxlbmd0aCksci5kYXRhIT1udWxsJiZyLmRhdGEuc2V0KGUuZGF0YSwwKX1yZXR1cm4gcn12YXIgVD1icjt2YXIga3I9ZnVuY3Rpb24oZSxBKXt2YXIgdD17fTtmb3IodmFyIHIgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmQS5pbmRleE9mKHIpPDAmJih0W3JdPWVbcl0pO2lmKGUhPW51bGwmJnR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzPT0iZnVuY3Rpb24iKWZvcih2YXIgYT0wLHI9T2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhlKTthPHIubGVuZ3RoO2ErKylBLmluZGV4T2YoclthXSk8MCYmT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKGUsclthXSkmJih0W3JbYV1dPWVbclthXV0pO3JldHVybiB0fSxUZT1jbGFzc3tjb25zdHJ1Y3RvcihBLHQpe3RoaXMuZmNuPXQsdGhpcy53b3JrZXJRdWV1ZT1uZXcgQXJyYXkoQSksdGhpcy53b3JrZXJRdWV1ZS5maWxsKG51bGwpLHRoaXMucnVuSW5mbz1bXX1ydW5UYXNrcyhBLHQ9bnVsbCl7bGV0IHI9e3Rhc2tRdWV1ZTpbXSxyZXN1bHRzOltdLGFkZGluZ1Rhc2tzOiExLHBvc3Rwb25lZDohMSxydW5uaW5nV29ya2VyczowLGluZGV4OjAsY29tcGxldGVkVGFza3M6MCxwcm9ncmVzc0NhbGxiYWNrOnQsY2FuY2VsZWQ6ITF9O3JldHVybiB0aGlzLnJ1bkluZm8ucHVzaChyKSxyLmluZGV4PXRoaXMucnVuSW5mby5sZW5ndGgtMSx7cHJvbWlzZTpuZXcgUHJvbWlzZSgoYSxvKT0+e3IucmVzb2x2ZT1hLHIucmVqZWN0PW8sci5yZXN1bHRzPW5ldyBBcnJheShBLmxlbmd0aCksci5jb21wbGV0ZWRUYXNrcz0wLHIuYWRkaW5nVGFza3M9ITAsQS5mb3JFYWNoKChpLGwpPT57dGhpcy5hZGRUYXNrKHIuaW5kZXgsbCxpKX0pLHIuYWRkaW5nVGFza3M9ITF9KSxydW5JZDpyLmluZGV4fX10ZXJtaW5hdGVXb3JrZXJzKCl7Zm9yKGxldCBBPTA7QTx0aGlzLndvcmtlclF1ZXVlLmxlbmd0aDtBKyspe2xldCB0PXRoaXMud29ya2VyUXVldWVbQV07dD8udGVybWluYXRlKCksdGhpcy53b3JrZXJRdWV1ZVtBXT1udWxsfX1jYW5jZWwoQSl7bGV0IHQ9dGhpcy5ydW5JbmZvW0FdO3QhPW51bGwmJih0LmNhbmNlbGVkPSEwKX1hZGRUYXNrKEEsdCxyKXtsZXQgYT10aGlzLnJ1bkluZm9bQV07aWYoYT8uY2FuY2VsZWQ9PT0hMCl7YS5yZWplY3QoIlJlbWFpbmluZyB0YXNrcyBjYW5jZWxlZCIpLHRoaXMuY2xlYXJUYXNrKGEuaW5kZXgpO3JldHVybn1pZih0aGlzLndvcmtlclF1ZXVlLmxlbmd0aD4wKXtsZXQgbz10aGlzLndvcmtlclF1ZXVlLnBvcCgpO2EucnVubmluZ1dvcmtlcnMrKyx0aGlzLmZjbihvLC4uLnIpLnRoZW4oaT0+e3Zhcnt3ZWJXb3JrZXI6bH09aSxmPWtyKGksWyJ3ZWJXb3JrZXIiXSk7aWYodGhpcy53b3JrZXJRdWV1ZS5wdXNoKGwpLHRoaXMucnVuSW5mb1tBXSE9PW51bGwpe2lmKGEucnVubmluZ1dvcmtlcnMtLSxhLnJlc3VsdHNbdF09ZixhLmNvbXBsZXRlZFRhc2tzKyssYS5wcm9ncmVzc0NhbGxiYWNrIT1udWxsJiZhLnByb2dyZXNzQ2FsbGJhY2soYS5jb21wbGV0ZWRUYXNrcyxhLnJlc3VsdHMubGVuZ3RoKSxhLnRhc2tRdWV1ZS5sZW5ndGg+MCl7bGV0IGc9YS50YXNrUXVldWUuc2hpZnQoKTt0aGlzLmFkZFRhc2soQSxnWzBdLGdbMV0pfWVsc2UgaWYoIWEuYWRkaW5nVGFza3MmJmEucnVubmluZ1dvcmtlcnM9PT0wKXtsZXQgZz1hLnJlc3VsdHM7YS5yZXNvbHZlKGcpLHRoaXMuY2xlYXJUYXNrKGEuaW5kZXgpfX19KS5jYXRjaChpPT57YS5yZWplY3QoaSksdGhpcy5jbGVhclRhc2soYS5pbmRleCl9KX1lbHNlIGEucnVubmluZ1dvcmtlcnMhPT0wfHxhLnBvc3Rwb25lZD9hLnRhc2tRdWV1ZS5wdXNoKFt0LHJdKTooYS5wb3N0cG9uZWQ9ITAsc2V0VGltZW91dCgoKT0+e2EucG9zdHBvbmVkPSExLHRoaXMuYWRkVGFzayhhLmluZGV4LHQscil9LDUwKSl9Y2xlYXJUYXNrKEEpe3RoaXMucnVuSW5mb1tBXS5yZXN1bHRzPVtdLHRoaXMucnVuSW5mb1tBXS50YXNrUXVldWU9W10sdGhpcy5ydW5JbmZvW0FdLnByb2dyZXNzQ2FsbGJhY2s9bnVsbCx0aGlzLnJ1bkluZm9bQV0uY2FuY2VsZWQ9bnVsbCx0aGlzLnJ1bkluZm9bQV0ucmVqZWN0PSgpPT57fSx0aGlzLnJ1bkluZm9bQV0ucmVzb2x2ZT0oKT0+e319fSxKZT1UZTt2YXIgRHI9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIEZyKGUpe2lmKGU9PW51bGwpcmV0dXJuW107bGV0IEE9W107Zm9yKGxldCB0PTA7dDxlLmxlbmd0aDt0Kyspe2xldCByPU9yKGVbdF0pO3IhPT1udWxsJiZBLnB1c2gocil9cmV0dXJuIEF9ZnVuY3Rpb24gT3IoZSl7aWYoZT09bnVsbClyZXR1cm4gbnVsbDtsZXQgQT1udWxsO3JldHVybiBlLmJ1ZmZlciE9PXZvaWQgMD9BPWUuYnVmZmVyOmUuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKEE9ZSksRHImJkEgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOkF9dmFyIGx0PUZyO2Z1bmN0aW9uIGllKGUsQSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUuYXBwbHkoQSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6VXJ9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOkhlfT1PYmplY3QsY2U9KGU9PkE9PntsZXQgdD1Vci5jYWxsKEEpO3JldHVybiBlW3RdfHwoZVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSkseD1lPT4oZT1lLnRvTG93ZXJDYXNlKCksQT0+Y2UoQSk9PT1lKSxkZT1lPT5BPT50eXBlb2YgQT09PWUse2lzQXJyYXk6an09QXJyYXksYWU9ZGUoInVuZGVmaW5lZCIpO2Z1bmN0aW9uIFNyKGUpe3JldHVybiBlIT09bnVsbCYmIWFlKGUpJiZlLmNvbnN0cnVjdG9yIT09bnVsbCYmIWFlKGUuY29uc3RydWN0b3IpJiZQKGUuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZlLmNvbnN0cnVjdG9yLmlzQnVmZmVyKGUpfXZhciBtdD14KCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIFdyKGUpe2xldCBBO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/QT1BcnJheUJ1ZmZlci5pc1ZpZXcoZSk6QT1lJiZlLmJ1ZmZlciYmbXQoZS5idWZmZXIpLEF9dmFyIE5yPWRlKCJzdHJpbmciKSxQPWRlKCJmdW5jdGlvbiIpLHV0PWRlKCJudW1iZXIiKSxCZT1lPT5lIT09bnVsbCYmdHlwZW9mIGU9PSJvYmplY3QiLFByPWU9PmU9PT0hMHx8ZT09PSExLGZlPWU9PntpZihjZShlKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBBPUhlKGUpO3JldHVybihBPT09bnVsbHx8QT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihBKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBlKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gZSl9LHhyPXgoIkRhdGUiKSxHcj14KCJGaWxlIiksVHI9eCgiQmxvYiIpLEpyPXgoIkZpbGVMaXN0IiksTHI9ZT0+QmUoZSkmJlAoZS5waXBlKSxNcj1lPT57bGV0IEE7cmV0dXJuIGUmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJmUgaW5zdGFuY2VvZiBGb3JtRGF0YXx8UChlLmFwcGVuZCkmJigoQT1jZShlKSk9PT0iZm9ybWRhdGEifHxBPT09Im9iamVjdCImJlAoZS50b1N0cmluZykmJmUudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sSHI9eCgiVVJMU2VhcmNoUGFyYW1zIiksWXI9ZT0+ZS50cmltP2UudHJpbSgpOmUucmVwbGFjZSgvXltcc1x1RkVGRlx4QTBdK3xbXHNcdUZFRkZceEEwXSskL2csIiIpO2Z1bmN0aW9uIG9lKGUsQSx7YWxsT3duS2V5czp0PSExfT17fSl7aWYoZT09PW51bGx8fHR5cGVvZiBlPiJ1IilyZXR1cm47bGV0IHIsYTtpZih0eXBlb2YgZSE9Im9iamVjdCImJihlPVtlXSksaihlKSlmb3Iocj0wLGE9ZS5sZW5ndGg7cjxhO3IrKylBLmNhbGwobnVsbCxlW3JdLHIsZSk7ZWxzZXtsZXQgbz10P09iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGUpOk9iamVjdC5rZXlzKGUpLGk9by5sZW5ndGgsbDtmb3Iocj0wO3I8aTtyKyspbD1vW3JdLEEuY2FsbChudWxsLGVbbF0sbCxlKX19ZnVuY3Rpb24gZnQoZSxBKXtBPUEudG9Mb3dlckNhc2UoKTtsZXQgdD1PYmplY3Qua2V5cyhlKSxyPXQubGVuZ3RoLGE7Zm9yKDtyLS0gPjA7KWlmKGE9dFtyXSxBPT09YS50b0xvd2VyQ2FzZSgpKXJldHVybiBhO3JldHVybiBudWxsfXZhciBjdD0oKCk9PnR5cGVvZiBnbG9iYWxUaGlzPCJ1Ij9nbG9iYWxUaGlzOnR5cGVvZiBzZWxmPCJ1Ij9zZWxmOnR5cGVvZiB3aW5kb3c8InUiP3dpbmRvdzpnbG9iYWwpKCksZHQ9ZT0+IWFlKGUpJiZlIT09Y3Q7ZnVuY3Rpb24gTWUoKXtsZXR7Y2FzZWxlc3M6ZX09ZHQodGhpcykmJnRoaXN8fHt9LEE9e30sdD0ocixhKT0+e2xldCBvPWUmJmZ0KEEsYSl8fGE7ZmUoQVtvXSkmJmZlKHIpP0Fbb109TWUoQVtvXSxyKTpmZShyKT9BW29dPU1lKHt9LHIpOmoocik/QVtvXT1yLnNsaWNlKCk6QVtvXT1yfTtmb3IobGV0IHI9MCxhPWFyZ3VtZW50cy5sZW5ndGg7cjxhO3IrKylhcmd1bWVudHNbcl0mJm9lKGFyZ3VtZW50c1tyXSx0KTtyZXR1cm4gQX12YXIgcXI9KGUsQSx0LHthbGxPd25LZXlzOnJ9PXt9KT0+KG9lKEEsKGEsbyk9Pnt0JiZQKGEpP2Vbb109aWUoYSx0KTplW29dPWF9LHthbGxPd25LZXlzOnJ9KSxlKSx2cj1lPT4oZS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihlPWUuc2xpY2UoMSkpLGUpLEtyPShlLEEsdCxyKT0+e2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoQS5wcm90b3R5cGUsciksZS5wcm90b3R5cGUuY29uc3RydWN0b3I9ZSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwic3VwZXIiLHt2YWx1ZTpBLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oZS5wcm90b3R5cGUsdCl9LGpyPShlLEEsdCxyKT0+e2xldCBhLG8saSxsPXt9O2lmKEE9QXx8e30sZT09bnVsbClyZXR1cm4gQTtkb3tmb3IoYT1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhlKSxvPWEubGVuZ3RoO28tLSA+MDspaT1hW29dLCghcnx8cihpLGUsQSkpJiYhbFtpXSYmKEFbaV09ZVtpXSxsW2ldPSEwKTtlPXQhPT0hMSYmSGUoZSl9d2hpbGUoZSYmKCF0fHx0KGUsQSkpJiZlIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIEF9LF9yPShlLEEsdCk9PntlPVN0cmluZyhlKSwodD09PXZvaWQgMHx8dD5lLmxlbmd0aCkmJih0PWUubGVuZ3RoKSx0LT1BLmxlbmd0aDtsZXQgcj1lLmluZGV4T2YoQSx0KTtyZXR1cm4gciE9PS0xJiZyPT09dH0senI9ZT0+e2lmKCFlKXJldHVybiBudWxsO2lmKGooZSkpcmV0dXJuIGU7bGV0IEE9ZS5sZW5ndGg7aWYoIXV0KEEpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShBKTtmb3IoO0EtLSA+MDspdFtBXT1lW0FdO3JldHVybiB0fSxWcj0oZT0+QT0+ZSYmQSBpbnN0YW5jZW9mIGUpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmSGUoVWludDhBcnJheSkpLFpyPShlLEEpPT57bGV0IHI9KGUmJmVbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChlKSxhO2Zvcig7KGE9ci5uZXh0KCkpJiYhYS5kb25lOyl7bGV0IG89YS52YWx1ZTtBLmNhbGwoZSxvWzBdLG9bMV0pfX0sWHI9KGUsQSk9PntsZXQgdCxyPVtdO2Zvcig7KHQ9ZS5leGVjKEEpKSE9PW51bGw7KXIucHVzaCh0KTtyZXR1cm4gcn0sJHI9eCgiSFRNTEZvcm1FbGVtZW50IiksZWk9ZT0+ZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xzXShbYS16XGRdKShcdyopL2csZnVuY3Rpb24odCxyLGEpe3JldHVybiByLnRvVXBwZXJDYXNlKCkrYX0pLGd0PSgoe2hhc093blByb3BlcnR5OmV9KT0+KEEsdCk9PmUuY2FsbChBLHQpKShPYmplY3QucHJvdG90eXBlKSxBaT14KCJSZWdFeHAiKSxCdD0oZSxBKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKGUpLHI9e307b2UodCwoYSxvKT0+e2xldCBpOyhpPUEoYSxvLGUpKSE9PSExJiYocltvXT1pfHxhKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGUscil9LHRpPWU9PntCdChlLChBLHQpPT57aWYoUChlKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKHQpIT09LTEpcmV0dXJuITE7bGV0IHI9ZVt0XTtpZihQKHIpKXtpZihBLmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIEEpe0Eud3JpdGFibGU9ITE7cmV0dXJufUEuc2V0fHwoQS5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgJyIrdCsiJyIpfSl9fSl9LHJpPShlLEEpPT57bGV0IHQ9e30scj1hPT57YS5mb3JFYWNoKG89Pnt0W29dPSEwfSl9O3JldHVybiBqKGUpP3IoZSk6cihTdHJpbmcoZSkuc3BsaXQoQSkpLHR9LGlpPSgpPT57fSxhaT0oZSxBKT0+KGU9K2UsTnVtYmVyLmlzRmluaXRlKGUpP2U6QSksTGU9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6IixwdD0iMDEyMzQ1Njc4OSIsQ3Q9e0RJR0lUOnB0LEFMUEhBOkxlLEFMUEhBX0RJR0lUOkxlK0xlLnRvVXBwZXJDYXNlKCkrcHR9LG9pPShlPTE2LEE9Q3QuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpyfT1BO2Zvcig7ZS0tOyl0Kz1BW01hdGgucmFuZG9tKCkqcnwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gbmkoZSl7cmV0dXJuISEoZSYmUChlLmFwcGVuZCkmJmVbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJmVbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIHNpPWU9PntsZXQgQT1uZXcgQXJyYXkoMTApLHQ9KHIsYSk9PntpZihCZShyKSl7aWYoQS5pbmRleE9mKHIpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gcikpe0FbYV09cjtsZXQgbz1qKHIpP1tdOnt9O3JldHVybiBvZShyLChpLGwpPT57bGV0IGY9dChpLGErMSk7IWFlKGYpJiYob1tsXT1mKX0pLEFbYV09dm9pZCAwLG99fXJldHVybiByfTtyZXR1cm4gdChlLDApfSxJaT14KCJBc3luY0Z1bmN0aW9uIiksbGk9ZT0+ZSYmKEJlKGUpfHxQKGUpKSYmUChlLnRoZW4pJiZQKGUuY2F0Y2gpLGM9e2lzQXJyYXk6aixpc0FycmF5QnVmZmVyOm10LGlzQnVmZmVyOlNyLGlzRm9ybURhdGE6TXIsaXNBcnJheUJ1ZmZlclZpZXc6V3IsaXNTdHJpbmc6TnIsaXNOdW1iZXI6dXQsaXNCb29sZWFuOlByLGlzT2JqZWN0OkJlLGlzUGxhaW5PYmplY3Q6ZmUsaXNVbmRlZmluZWQ6YWUsaXNEYXRlOnhyLGlzRmlsZTpHcixpc0Jsb2I6VHIsaXNSZWdFeHA6QWksaXNGdW5jdGlvbjpQLGlzU3RyZWFtOkxyLGlzVVJMU2VhcmNoUGFyYW1zOkhyLGlzVHlwZWRBcnJheTpWcixpc0ZpbGVMaXN0OkpyLGZvckVhY2g6b2UsbWVyZ2U6TWUsZXh0ZW5kOnFyLHRyaW06WXIsc3RyaXBCT006dnIsaW5oZXJpdHM6S3IsdG9GbGF0T2JqZWN0OmpyLGtpbmRPZjpjZSxraW5kT2ZUZXN0OngsZW5kc1dpdGg6X3IsdG9BcnJheTp6cixmb3JFYWNoRW50cnk6WnIsbWF0Y2hBbGw6WHIsaXNIVE1MRm9ybTokcixoYXNPd25Qcm9wZXJ0eTpndCxoYXNPd25Qcm9wOmd0LHJlZHVjZURlc2NyaXB0b3JzOkJ0LGZyZWV6ZU1ldGhvZHM6dGksdG9PYmplY3RTZXQ6cmksdG9DYW1lbENhc2U6ZWksbm9vcDppaSx0b0Zpbml0ZU51bWJlcjphaSxmaW5kS2V5OmZ0LGdsb2JhbDpjdCxpc0NvbnRleHREZWZpbmVkOmR0LEFMUEhBQkVUOkN0LGdlbmVyYXRlU3RyaW5nOm9pLGlzU3BlY0NvbXBsaWFudEZvcm06bmksdG9KU09OT2JqZWN0OnNpLGlzQXN5bmNGbjpJaSxpc1RoZW5hYmxlOmxpfTtmdW5jdGlvbiBfKGUsQSx0LHIsYSl7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPWUsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixBJiYodGhpcy5jb2RlPUEpLHQmJih0aGlzLmNvbmZpZz10KSxyJiYodGhpcy5yZXF1ZXN0PXIpLGEmJih0aGlzLnJlc3BvbnNlPWEpfWMuaW5oZXJpdHMoXyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOmMudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIHl0PV8ucHJvdG90eXBlLEV0PXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goZT0+e0V0W2VdPXt2YWx1ZTplfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKF8sRXQpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh5dCwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtfLmZyb209KGUsQSx0LHIsYSxvKT0+e2xldCBpPU9iamVjdC5jcmVhdGUoeXQpO3JldHVybiBjLnRvRmxhdE9iamVjdChlLGksZnVuY3Rpb24oZil7cmV0dXJuIGYhPT1FcnJvci5wcm90b3R5cGV9LGw9PmwhPT0iaXNBeGlvc0Vycm9yIiksXy5jYWxsKGksZS5tZXNzYWdlLEEsdCxyLGEpLGkuY2F1c2U9ZSxpLm5hbWU9ZS5uYW1lLG8mJk9iamVjdC5hc3NpZ24oaSxvKSxpfTt2YXIgaD1fO3ZhciBDZT1udWxsO2Z1bmN0aW9uIFllKGUpe3JldHVybiBjLmlzUGxhaW5PYmplY3QoZSl8fGMuaXNBcnJheShlKX1mdW5jdGlvbiBodChlKXtyZXR1cm4gYy5lbmRzV2l0aChlLCJbXSIpP2Uuc2xpY2UoMCwtMik6ZX1mdW5jdGlvbiBRdChlLEEsdCl7cmV0dXJuIGU/ZS5jb25jYXQoQSkubWFwKGZ1bmN0aW9uKGEsbyl7cmV0dXJuIGE9aHQoYSksIXQmJm8/IlsiK2ErIl0iOmF9KS5qb2luKHQ/Ii4iOiIiKTpBfWZ1bmN0aW9uIGdpKGUpe3JldHVybiBjLmlzQXJyYXkoZSkmJiFlLnNvbWUoWWUpfXZhciBwaT1jLnRvRmxhdE9iamVjdChjLHt9LG51bGwsZnVuY3Rpb24oQSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KEEpfSk7ZnVuY3Rpb24gbWkoZSxBLHQpe2lmKCFjLmlzT2JqZWN0KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO0E9QXx8bmV3KENlfHxGb3JtRGF0YSksdD1jLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oZCxFKXtyZXR1cm4hYy5pc1VuZGVmaW5lZChFW2RdKX0pO2xldCByPXQubWV0YVRva2VucyxhPXQudmlzaXRvcnx8bixvPXQuZG90cyxpPXQuaW5kZXhlcyxmPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJmMuaXNTcGVjQ29tcGxpYW50Rm9ybShBKTtpZighYy5pc0Z1bmN0aW9uKGEpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gZyhJKXtpZihJPT09bnVsbClyZXR1cm4iIjtpZihjLmlzRGF0ZShJKSlyZXR1cm4gSS50b0lTT1N0cmluZygpO2lmKCFmJiZjLmlzQmxvYihJKSl0aHJvdyBuZXcgaCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gYy5pc0FycmF5QnVmZmVyKEkpfHxjLmlzVHlwZWRBcnJheShJKT9mJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbSV0pOkJ1ZmZlci5mcm9tKEkpOkl9ZnVuY3Rpb24gbihJLGQsRSl7bGV0IFI9STtpZihJJiYhRSYmdHlwZW9mIEk9PSJvYmplY3QiKXtpZihjLmVuZHNXaXRoKGQsInt9IikpZD1yP2Q6ZC5zbGljZSgwLC0yKSxJPUpTT04uc3RyaW5naWZ5KEkpO2Vsc2UgaWYoYy5pc0FycmF5KEkpJiZnaShJKXx8KGMuaXNGaWxlTGlzdChJKXx8Yy5lbmRzV2l0aChkLCJbXSIpKSYmKFI9Yy50b0FycmF5KEkpKSlyZXR1cm4gZD1odChkKSxSLmZvckVhY2goZnVuY3Rpb24oayxXZSl7IShjLmlzVW5kZWZpbmVkKGspfHxrPT09bnVsbCkmJkEuYXBwZW5kKGk9PT0hMD9RdChbZF0sV2Usbyk6aT09PW51bGw/ZDpkKyJbXSIsZyhrKSl9KSwhMX1yZXR1cm4gWWUoSSk/ITA6KEEuYXBwZW5kKFF0KEUsZCxvKSxnKEkpKSwhMSl9bGV0IHU9W10scD1PYmplY3QuYXNzaWduKHBpLHtkZWZhdWx0VmlzaXRvcjpuLGNvbnZlcnRWYWx1ZTpnLGlzVmlzaXRhYmxlOlllfSk7ZnVuY3Rpb24gcyhJLGQpe2lmKCFjLmlzVW5kZWZpbmVkKEkpKXtpZih1LmluZGV4T2YoSSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrZC5qb2luKCIuIikpO3UucHVzaChJKSxjLmZvckVhY2goSSxmdW5jdGlvbihSLHcpeyghKGMuaXNVbmRlZmluZWQoUil8fFI9PT1udWxsKSYmYS5jYWxsKEEsUixjLmlzU3RyaW5nKHcpP3cudHJpbSgpOncsZCxwKSk9PT0hMCYmcyhSLGQ/ZC5jb25jYXQodyk6W3ddKX0pLHUucG9wKCl9fWlmKCFjLmlzT2JqZWN0KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gcyhlKSxBfXZhciBKPW1pO2Z1bmN0aW9uIHd0KGUpe2xldCBBPXsiISI6IiUyMSIsIiciOiIlMjciLCIoIjoiJTI4IiwiKSI6IiUyOSIsIn4iOiIlN0UiLCIlMjAiOiIrIiwiJTAwIjoiXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KGUpLnJlcGxhY2UoL1shJygpfl18JTIwfCUwMC9nLGZ1bmN0aW9uKHIpe3JldHVybiBBW3JdfSl9ZnVuY3Rpb24gUnQoZSxBKXt0aGlzLl9wYWlycz1bXSxlJiZKKGUsdGhpcyxBKX12YXIgYnQ9UnQucHJvdG90eXBlO2J0LmFwcGVuZD1mdW5jdGlvbihBLHQpe3RoaXMuX3BhaXJzLnB1c2goW0EsdF0pfTtidC50b1N0cmluZz1mdW5jdGlvbihBKXtsZXQgdD1BP2Z1bmN0aW9uKHIpe3JldHVybiBBLmNhbGwodGhpcyxyLHd0KX06d3Q7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihhKXtyZXR1cm4gdChhWzBdKSsiPSIrdChhWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIHllPVJ0O2Z1bmN0aW9uIHVpKGUpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoZSkucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfWZ1bmN0aW9uIG5lKGUsQSx0KXtpZighQSlyZXR1cm4gZTtsZXQgcj10JiZ0LmVuY29kZXx8dWksYT10JiZ0LnNlcmlhbGl6ZSxvO2lmKGE/bz1hKEEsdCk6bz1jLmlzVVJMU2VhcmNoUGFyYW1zKEEpP0EudG9TdHJpbmcoKTpuZXcgeWUoQSx0KS50b1N0cmluZyhyKSxvKXtsZXQgaT1lLmluZGV4T2YoIiMiKTtpIT09LTEmJihlPWUuc2xpY2UoMCxpKSksZSs9KGUuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikrb31yZXR1cm4gZX12YXIgcWU9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZShBLHQscil7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOkEscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpyP3Iuc3luY2hyb25vdXM6ITEscnVuV2hlbjpyP3IucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdChBKXt0aGlzLmhhbmRsZXJzW0FdJiYodGhpcy5oYW5kbGVyc1tBXT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKEEpe2MuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHIpe3IhPT1udWxsJiZBKHIpfSl9fSx2ZT1xZTt2YXIgRWU9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9O3ZhciBrdD10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6eWU7dmFyIER0PXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgRnQ9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgZmk9KCgpPT57bGV0IGU7cmV0dXJuIHR5cGVvZiBuYXZpZ2F0b3I8InUiJiYoKGU9bmF2aWdhdG9yLnByb2R1Y3QpPT09IlJlYWN0TmF0aXZlInx8ZT09PSJOYXRpdmVTY3JpcHQifHxlPT09Ik5TIik/ITE6dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSJ9KSgpLGNpPSgoKT0+dHlwZW9mIFdvcmtlckdsb2JhbFNjb3BlPCJ1IiYmc2VsZiBpbnN0YW5jZW9mIFdvcmtlckdsb2JhbFNjb3BlJiZ0eXBlb2Ygc2VsZi5pbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKSgpLEY9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6a3QsRm9ybURhdGE6RHQsQmxvYjpGdH0saXNTdGFuZGFyZEJyb3dzZXJFbnY6ZmksaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6Y2kscHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O2Z1bmN0aW9uIEtlKGUsQSl7cmV0dXJuIEooZSxuZXcgRi5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKHQscixhLG8pe3JldHVybiBGLmlzTm9kZSYmYy5pc0J1ZmZlcih0KT8odGhpcy5hcHBlbmQocix0LnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOm8uZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sQSkpfWZ1bmN0aW9uIGRpKGUpe3JldHVybiBjLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxlKS5tYXAoQT0+QVswXT09PSJbXSI/IiI6QVsxXXx8QVswXSl9ZnVuY3Rpb24gQmkoZSl7bGV0IEE9e30sdD1PYmplY3Qua2V5cyhlKSxyLGE9dC5sZW5ndGgsbztmb3Iocj0wO3I8YTtyKyspbz10W3JdLEFbb109ZVtvXTtyZXR1cm4gQX1mdW5jdGlvbiBDaShlKXtmdW5jdGlvbiBBKHQscixhLG8pe2xldCBpPXRbbysrXSxsPU51bWJlci5pc0Zpbml0ZSgraSksZj1vPj10Lmxlbmd0aDtyZXR1cm4gaT0haSYmYy5pc0FycmF5KGEpP2EubGVuZ3RoOmksZj8oYy5oYXNPd25Qcm9wKGEsaSk/YVtpXT1bYVtpXSxyXTphW2ldPXIsIWwpOigoIWFbaV18fCFjLmlzT2JqZWN0KGFbaV0pKSYmKGFbaV09W10pLEEodCxyLGFbaV0sbykmJmMuaXNBcnJheShhW2ldKSYmKGFbaV09QmkoYVtpXSkpLCFsKX1pZihjLmlzRm9ybURhdGEoZSkmJmMuaXNGdW5jdGlvbihlLmVudHJpZXMpKXtsZXQgdD17fTtyZXR1cm4gYy5mb3JFYWNoRW50cnkoZSwocixhKT0+e0EoZGkociksYSx0LDApfSksdH1yZXR1cm4gbnVsbH12YXIgUWU9Q2k7ZnVuY3Rpb24geWkoZSxBLHQpe2lmKGMuaXNTdHJpbmcoZSkpdHJ5e3JldHVybihBfHxKU09OLnBhcnNlKShlKSxjLnRyaW0oZSl9Y2F0Y2gocil7aWYoci5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyByfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoZSl9dmFyIGplPXt0cmFuc2l0aW9uYWw6RWUsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihBLHQpe2xldCByPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIsYT1yLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxvPWMuaXNPYmplY3QoQSk7aWYobyYmYy5pc0hUTUxGb3JtKEEpJiYoQT1uZXcgRm9ybURhdGEoQSkpLGMuaXNGb3JtRGF0YShBKSlyZXR1cm4gYSYmYT9KU09OLnN0cmluZ2lmeShRZShBKSk6QTtpZihjLmlzQXJyYXlCdWZmZXIoQSl8fGMuaXNCdWZmZXIoQSl8fGMuaXNTdHJlYW0oQSl8fGMuaXNGaWxlKEEpfHxjLmlzQmxvYihBKSlyZXR1cm4gQTtpZihjLmlzQXJyYXlCdWZmZXJWaWV3KEEpKXJldHVybiBBLmJ1ZmZlcjtpZihjLmlzVVJMU2VhcmNoUGFyYW1zKEEpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLEEudG9TdHJpbmcoKTtsZXQgbDtpZihvKXtpZihyLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiBLZShBLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKGw9Yy5pc0ZpbGVMaXN0KEEpKXx8ci5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBmPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gSihsP3siZmlsZXNbXSI6QX06QSxmJiZuZXcgZix0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIG98fGE/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSx5aShBKSk6QX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihBKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8amUudHJhbnNpdGlvbmFsLHI9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxhPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKEEmJmMuaXNTdHJpbmcoQSkmJihyJiYhdGhpcy5yZXNwb25zZVR5cGV8fGEpKXtsZXQgaT0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZhO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShBKX1jYXRjaChsKXtpZihpKXRocm93IGwubmFtZT09PSJTeW50YXhFcnJvciI/aC5mcm9tKGwsaC5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpsfX1yZXR1cm4gQX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6Ri5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6Ri5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKEEpe3JldHVybiBBPj0yMDAmJkE8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07Yy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLGU9PntqZS5oZWFkZXJzW2VdPXt9fSk7dmFyIHo9amU7dmFyIEVpPWMudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksT3Q9ZT0+e2xldCBBPXt9LHQscixhO3JldHVybiBlJiZlLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihpKXthPWkuaW5kZXhPZigiOiIpLHQ9aS5zdWJzdHJpbmcoMCxhKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPWkuc3Vic3RyaW5nKGErMSkudHJpbSgpLCEoIXR8fEFbdF0mJkVpW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/QVt0XT9BW3RdLnB1c2gocik6QVt0XT1bcl06QVt0XT1BW3RdP0FbdF0rIiwgIityOnIpfSksQX07dmFyIFV0PVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gc2UoZSl7cmV0dXJuIGUmJlN0cmluZyhlKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBoZShlKXtyZXR1cm4gZT09PSExfHxlPT1udWxsP2U6Yy5pc0FycmF5KGUpP2UubWFwKGhlKTpTdHJpbmcoZSl9ZnVuY3Rpb24gUWkoZSl7bGV0IEE9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9dC5leGVjKGUpOylBW3JbMV1dPXJbMl07cmV0dXJuIEF9dmFyIGhpPWU9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoZS50cmltKCkpO2Z1bmN0aW9uIF9lKGUsQSx0LHIsYSl7aWYoYy5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyxBLHQpO2lmKGEmJihBPXQpLCEhYy5pc1N0cmluZyhBKSl7aWYoYy5pc1N0cmluZyhyKSlyZXR1cm4gQS5pbmRleE9mKHIpIT09LTE7aWYoYy5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KEEpfX1mdW5jdGlvbiB3aShlKXtyZXR1cm4gZS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLChBLHQscik9PnQudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBSaShlLEEpe2xldCB0PWMudG9DYW1lbENhc2UoIiAiK0EpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KGUscit0LHt2YWx1ZTpmdW5jdGlvbihhLG8saSl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLEEsYSxvLGkpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBWPWNsYXNze2NvbnN0cnVjdG9yKEEpe0EmJnRoaXMuc2V0KEEpfXNldChBLHQscil7bGV0IGE9dGhpcztmdW5jdGlvbiBvKGwsZixnKXtsZXQgbj1zZShmKTtpZighbil0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IHU9Yy5maW5kS2V5KGEsbik7KCF1fHxhW3VdPT09dm9pZCAwfHxnPT09ITB8fGc9PT12b2lkIDAmJmFbdV0hPT0hMSkmJihhW3V8fGZdPWhlKGwpKX1sZXQgaT0obCxmKT0+Yy5mb3JFYWNoKGwsKGcsbik9Pm8oZyxuLGYpKTtyZXR1cm4gYy5pc1BsYWluT2JqZWN0KEEpfHxBIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9pKEEsdCk6Yy5pc1N0cmluZyhBKSYmKEE9QS50cmltKCkpJiYhaGkoQSk/aShPdChBKSx0KTpBIT1udWxsJiZvKHQsQSxyKSx0aGlzfWdldChBLHQpe2lmKEE9c2UoQSksQSl7bGV0IHI9Yy5maW5kS2V5KHRoaXMsQSk7aWYocil7bGV0IGE9dGhpc1tyXTtpZighdClyZXR1cm4gYTtpZih0PT09ITApcmV0dXJuIFFpKGEpO2lmKGMuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsYSxyKTtpZihjLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMoYSk7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhBLHQpe2lmKEE9c2UoQSksQSl7bGV0IHI9Yy5maW5kS2V5KHRoaXMsQSk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCF0fHxfZSh0aGlzLHRoaXNbcl0scix0KSkpfXJldHVybiExfWRlbGV0ZShBLHQpe2xldCByPXRoaXMsYT0hMTtmdW5jdGlvbiBvKGkpe2lmKGk9c2UoaSksaSl7bGV0IGw9Yy5maW5kS2V5KHIsaSk7bCYmKCF0fHxfZShyLHJbbF0sbCx0KSkmJihkZWxldGUgcltsXSxhPSEwKX19cmV0dXJuIGMuaXNBcnJheShBKT9BLmZvckVhY2gobyk6byhBKSxhfWNsZWFyKEEpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLHI9dC5sZW5ndGgsYT0hMTtmb3IoO3ItLTspe2xldCBvPXRbcl07KCFBfHxfZSh0aGlzLHRoaXNbb10sbyxBLCEwKSkmJihkZWxldGUgdGhpc1tvXSxhPSEwKX1yZXR1cm4gYX1ub3JtYWxpemUoQSl7bGV0IHQ9dGhpcyxyPXt9O3JldHVybiBjLmZvckVhY2godGhpcywoYSxvKT0+e2xldCBpPWMuZmluZEtleShyLG8pO2lmKGkpe3RbaV09aGUoYSksZGVsZXRlIHRbb107cmV0dXJufWxldCBsPUE/d2kobyk6U3RyaW5nKG8pLnRyaW0oKTtsIT09byYmZGVsZXRlIHRbb10sdFtsXT1oZShhKSxyW2xdPSEwfSksdGhpc31jb25jYXQoLi4uQSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uQSl9dG9KU09OKEEpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIGMuZm9yRWFjaCh0aGlzLChyLGEpPT57ciE9bnVsbCYmciE9PSExJiYodFthXT1BJiZjLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbQSx0XSk9PkErIjogIit0KS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShBKXtyZXR1cm4gQSBpbnN0YW5jZW9mIHRoaXM/QTpuZXcgdGhpcyhBKX1zdGF0aWMgY29uY2F0KEEsLi4udCl7bGV0IHI9bmV3IHRoaXMoQSk7cmV0dXJuIHQuZm9yRWFjaChhPT5yLnNldChhKSkscn1zdGF0aWMgYWNjZXNzb3IoQSl7bGV0IHI9KHRoaXNbVXRdPXRoaXNbVXRdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsYT10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBvKGkpe2xldCBsPXNlKGkpO3JbbF18fChSaShhLGkpLHJbbF09ITApfXJldHVybiBjLmlzQXJyYXkoQSk/QS5mb3JFYWNoKG8pOm8oQSksdGhpc319O1YuYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO2MucmVkdWNlRGVzY3JpcHRvcnMoVi5wcm90b3R5cGUsKHt2YWx1ZTplfSxBKT0+e2xldCB0PUFbMF0udG9VcHBlckNhc2UoKStBLnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PmUsc2V0KHIpe3RoaXNbdF09cn19fSk7Yy5mcmVlemVNZXRob2RzKFYpO3ZhciBVPVY7ZnVuY3Rpb24gSWUoZSxBKXtsZXQgdD10aGlzfHx6LHI9QXx8dCxhPVUuZnJvbShyLmhlYWRlcnMpLG89ci5kYXRhO3JldHVybiBjLmZvckVhY2goZSxmdW5jdGlvbihsKXtvPWwuY2FsbCh0LG8sYS5ub3JtYWxpemUoKSxBP0Euc3RhdHVzOnZvaWQgMCl9KSxhLm5vcm1hbGl6ZSgpLG99ZnVuY3Rpb24gbGUoZSl7cmV0dXJuISEoZSYmZS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBTdChlLEEsdCl7aC5jYWxsKHRoaXMsZT8/ImNhbmNlbGVkIixoLkVSUl9DQU5DRUxFRCxBLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9Yy5pbmhlcml0cyhTdCxoLHtfX0NBTkNFTF9fOiEwfSk7dmFyIEw9U3Q7ZnVuY3Rpb24gemUoZSxBLHQpe2xldCByPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IXJ8fHIodC5zdGF0dXMpP2UodCk6QShuZXcgaCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFtoLkVSUl9CQURfUkVRVUVTVCxoLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciBXdD1GLmlzU3RhbmRhcmRCcm93c2VyRW52P2Z1bmN0aW9uKCl7cmV0dXJue3dyaXRlOmZ1bmN0aW9uKHQscixhLG8saSxsKXtsZXQgZj1bXTtmLnB1c2godCsiPSIrZW5jb2RlVVJJQ29tcG9uZW50KHIpKSxjLmlzTnVtYmVyKGEpJiZmLnB1c2goImV4cGlyZXM9IituZXcgRGF0ZShhKS50b0dNVFN0cmluZygpKSxjLmlzU3RyaW5nKG8pJiZmLnB1c2goInBhdGg9IitvKSxjLmlzU3RyaW5nKGkpJiZmLnB1c2goImRvbWFpbj0iK2kpLGw9PT0hMCYmZi5wdXNoKCJzZWN1cmUiKSxkb2N1bWVudC5jb29raWU9Zi5qb2luKCI7ICIpfSxyZWFkOmZ1bmN0aW9uKHQpe2xldCByPWRvY3VtZW50LmNvb2tpZS5tYXRjaChuZXcgUmVnRXhwKCIoXnw7XFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIHI/ZGVjb2RlVVJJQ29tcG9uZW50KHJbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBWZShlKXtyZXR1cm4vXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KGUpfWZ1bmN0aW9uIFplKGUsQSl7cmV0dXJuIEE/ZS5yZXBsYWNlKC9cLyskLywiIikrIi8iK0EucmVwbGFjZSgvXlwvKy8sIiIpOmV9ZnVuY3Rpb24gZ2UoZSxBKXtyZXR1cm4gZSYmIVZlKEEpP1plKGUsQSk6QX12YXIgTnQ9Ri5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBBPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikscjtmdW5jdGlvbiBhKG8pe2xldCBpPW87cmV0dXJuIEEmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsaSksaT10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixpKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cPy8sIiIpOiIiLGhhc2g6dC5oYXNoP3QuaGFzaC5yZXBsYWNlKC9eIy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIHI9YSh3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oaSl7bGV0IGw9Yy5pc1N0cmluZyhpKT9hKGkpOmk7cmV0dXJuIGwucHJvdG9jb2w9PT1yLnByb3RvY29sJiZsLmhvc3Q9PT1yLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIFhlKGUpe2xldCBBPS9eKFstK1x3XXsxLDI1fSkoOj9cL1wvfDopLy5leGVjKGUpO3JldHVybiBBJiZBWzFdfHwiIn1mdW5jdGlvbiBiaShlLEEpe2U9ZXx8MTA7bGV0IHQ9bmV3IEFycmF5KGUpLHI9bmV3IEFycmF5KGUpLGE9MCxvPTAsaTtyZXR1cm4gQT1BIT09dm9pZCAwP0E6MWUzLGZ1bmN0aW9uKGYpe2xldCBnPURhdGUubm93KCksbj1yW29dO2l8fChpPWcpLHRbYV09ZixyW2FdPWc7bGV0IHU9byxwPTA7Zm9yKDt1IT09YTspcCs9dFt1KytdLHU9dSVlO2lmKGE9KGErMSklZSxhPT09byYmKG89KG8rMSklZSksZy1pPEEpcmV0dXJuO2xldCBzPW4mJmctbjtyZXR1cm4gcz9NYXRoLnJvdW5kKHAqMWUzL3MpOnZvaWQgMH19dmFyIFB0PWJpO2Z1bmN0aW9uIHh0KGUsQSl7bGV0IHQ9MCxyPVB0KDUwLDI1MCk7cmV0dXJuIGE9PntsZXQgbz1hLmxvYWRlZCxpPWEubGVuZ3RoQ29tcHV0YWJsZT9hLnRvdGFsOnZvaWQgMCxsPW8tdCxmPXIobCksZz1vPD1pO3Q9bztsZXQgbj17bG9hZGVkOm8sdG90YWw6aSxwcm9ncmVzczppP28vaTp2b2lkIDAsYnl0ZXM6bCxyYXRlOmZ8fHZvaWQgMCxlc3RpbWF0ZWQ6ZiYmaSYmZz8oaS1vKS9mOnZvaWQgMCxldmVudDphfTtuW0E/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsZShuKX19dmFyIGtpPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsR3Q9a2kmJmZ1bmN0aW9uKGUpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LHIpe2xldCBhPWUuZGF0YSxvPVUuZnJvbShlLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGk9ZS5yZXNwb25zZVR5cGUsbDtmdW5jdGlvbiBmKCl7ZS5jYW5jZWxUb2tlbiYmZS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShsKSxlLnNpZ25hbCYmZS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGwpfWxldCBnO2MuaXNGb3JtRGF0YShhKSYmKEYuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEYuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/by5zZXRDb250ZW50VHlwZSghMSk6by5nZXRDb250ZW50VHlwZSgvXlxzKm11bHRpcGFydFwvZm9ybS1kYXRhLyk/Yy5pc1N0cmluZyhnPW8uZ2V0Q29udGVudFR5cGUoKSkmJm8uc2V0Q29udGVudFR5cGUoZy5yZXBsYWNlKC9eXHMqKG11bHRpcGFydFwvZm9ybS1kYXRhKTsrLywiJDEiKSk6by5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YSIpKTtsZXQgbj1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoZS5hdXRoKXtsZXQgST1lLmF1dGgudXNlcm5hbWV8fCIiLGQ9ZS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChlLmF1dGgucGFzc3dvcmQpKToiIjtvLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYShJKyI6IitkKSl9bGV0IHU9Z2UoZS5iYXNlVVJMLGUudXJsKTtuLm9wZW4oZS5tZXRob2QudG9VcHBlckNhc2UoKSxuZSh1LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplciksITApLG4udGltZW91dD1lLnRpbWVvdXQ7ZnVuY3Rpb24gcCgpe2lmKCFuKXJldHVybjtsZXQgST1VLmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBuJiZuLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxFPXtkYXRhOiFpfHxpPT09InRleHQifHxpPT09Impzb24iP24ucmVzcG9uc2VUZXh0Om4ucmVzcG9uc2Usc3RhdHVzOm4uc3RhdHVzLHN0YXR1c1RleHQ6bi5zdGF0dXNUZXh0LGhlYWRlcnM6SSxjb25maWc6ZSxyZXF1ZXN0Om59O3plKGZ1bmN0aW9uKHcpe3QodyksZigpfSxmdW5jdGlvbih3KXtyKHcpLGYoKX0sRSksbj1udWxsfWlmKCJvbmxvYWRlbmQiaW4gbj9uLm9ubG9hZGVuZD1wOm4ub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IW58fG4ucmVhZHlTdGF0ZSE9PTR8fG4uc3RhdHVzPT09MCYmIShuLnJlc3BvbnNlVVJMJiZuLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChwKX0sbi5vbmFib3J0PWZ1bmN0aW9uKCl7biYmKHIobmV3IGgoIlJlcXVlc3QgYWJvcnRlZCIsaC5FQ09OTkFCT1JURUQsZSxuKSksbj1udWxsKX0sbi5vbmVycm9yPWZ1bmN0aW9uKCl7cihuZXcgaCgiTmV0d29yayBFcnJvciIsaC5FUlJfTkVUV09SSyxlLG4pKSxuPW51bGx9LG4ub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IGQ9ZS50aW1lb3V0PyJ0aW1lb3V0IG9mICIrZS50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLEU9ZS50cmFuc2l0aW9uYWx8fEVlO2UudGltZW91dEVycm9yTWVzc2FnZSYmKGQ9ZS50aW1lb3V0RXJyb3JNZXNzYWdlKSxyKG5ldyBoKGQsRS5jbGFyaWZ5VGltZW91dEVycm9yP2guRVRJTUVET1VUOmguRUNPTk5BQk9SVEVELGUsbikpLG49bnVsbH0sRi5pc1N0YW5kYXJkQnJvd3NlckVudil7bGV0IEk9TnQodSkmJmUueHNyZkNvb2tpZU5hbWUmJld0LnJlYWQoZS54c3JmQ29va2llTmFtZSk7SSYmby5zZXQoZS54c3JmSGVhZGVyTmFtZSxJKX1hPT09dm9pZCAwJiZvLnNldENvbnRlbnRUeXBlKG51bGwpLCJzZXRSZXF1ZXN0SGVhZGVyImluIG4mJmMuZm9yRWFjaChvLnRvSlNPTigpLGZ1bmN0aW9uKGQsRSl7bi5zZXRSZXF1ZXN0SGVhZGVyKEUsZCl9KSxjLmlzVW5kZWZpbmVkKGUud2l0aENyZWRlbnRpYWxzKXx8KG4ud2l0aENyZWRlbnRpYWxzPSEhZS53aXRoQ3JlZGVudGlhbHMpLGkmJmkhPT0ianNvbiImJihuLnJlc3BvbnNlVHlwZT1lLnJlc3BvbnNlVHlwZSksdHlwZW9mIGUub25Eb3dubG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZuLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIix4dChlLm9uRG93bmxvYWRQcm9ncmVzcywhMCkpLHR5cGVvZiBlLm9uVXBsb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm4udXBsb2FkJiZuLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIseHQoZS5vblVwbG9hZFByb2dyZXNzKSksKGUuY2FuY2VsVG9rZW58fGUuc2lnbmFsKSYmKGw9ST0+e24mJihyKCFJfHxJLnR5cGU/bmV3IEwobnVsbCxlLG4pOkkpLG4uYWJvcnQoKSxuPW51bGwpfSxlLmNhbmNlbFRva2VuJiZlLmNhbmNlbFRva2VuLnN1YnNjcmliZShsKSxlLnNpZ25hbCYmKGUuc2lnbmFsLmFib3J0ZWQ/bCgpOmUuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixsKSkpO2xldCBzPVhlKHUpO2lmKHMmJkYucHJvdG9jb2xzLmluZGV4T2Yocyk9PT0tMSl7cihuZXcgaCgiVW5zdXBwb3J0ZWQgcHJvdG9jb2wgIitzKyI6IixoLkVSUl9CQURfUkVRVUVTVCxlKSk7cmV0dXJufW4uc2VuZChhfHxudWxsKX0pfTt2YXIgJGU9e2h0dHA6Q2UseGhyOkd0fTtjLmZvckVhY2goJGUsKGUsQSk9PntpZihlKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIm5hbWUiLHt2YWx1ZTpBfSl9Y2F0Y2h7fU9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJhZGFwdGVyTmFtZSIse3ZhbHVlOkF9KX19KTt2YXIgVHQ9ZT0+YC0gJHtlfWAsRGk9ZT0+Yy5pc0Z1bmN0aW9uKGUpfHxlPT09bnVsbHx8ZT09PSExLHdlPXtnZXRBZGFwdGVyOmU9PntlPWMuaXNBcnJheShlKT9lOltlXTtsZXR7bGVuZ3RoOkF9PWUsdCxyLGE9e307Zm9yKGxldCBvPTA7bzxBO28rKyl7dD1lW29dO2xldCBpO2lmKHI9dCwhRGkodCkmJihyPSRlWyhpPVN0cmluZyh0KSkudG9Mb3dlckNhc2UoKV0scj09PXZvaWQgMCkpdGhyb3cgbmV3IGgoYFVua25vd24gYWRhcHRlciAnJHtpfSdgKTtpZihyKWJyZWFrO2FbaXx8IiMiK29dPXJ9aWYoIXIpe2xldCBvPU9iamVjdC5lbnRyaWVzKGEpLm1hcCgoW2wsZl0pPT5gYWRhcHRlciAke2x9IGArKGY9PT0hMT8iaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZW52aXJvbm1lbnQiOiJpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZCIpKSxpPUE/by5sZW5ndGg+MT9gc2luY2UgOgpgK28ubWFwKFR0KS5qb2luKGAKYCk6IiAiK1R0KG9bMF0pOiJhcyBubyBhZGFwdGVyIHNwZWNpZmllZCI7dGhyb3cgbmV3IGgoIlRoZXJlIGlzIG5vIHN1aXRhYmxlIGFkYXB0ZXIgdG8gZGlzcGF0Y2ggdGhlIHJlcXVlc3QgIitpLCJFUlJfTk9UX1NVUFBPUlQiKX1yZXR1cm4gcn0sYWRhcHRlcnM6JGV9O2Z1bmN0aW9uIGVBKGUpe2lmKGUuY2FuY2VsVG9rZW4mJmUuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLGUuc2lnbmFsJiZlLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyBMKG51bGwsZSl9ZnVuY3Rpb24gUmUoZSl7cmV0dXJuIGVBKGUpLGUuaGVhZGVycz1VLmZyb20oZS5oZWFkZXJzKSxlLmRhdGE9SWUuY2FsbChlLGUudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKGUubWV0aG9kKSE9PS0xJiZlLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLHdlLmdldEFkYXB0ZXIoZS5hZGFwdGVyfHx6LmFkYXB0ZXIpKGUpLnRoZW4oZnVuY3Rpb24ocil7cmV0dXJuIGVBKGUpLHIuZGF0YT1JZS5jYWxsKGUsZS50cmFuc2Zvcm1SZXNwb25zZSxyKSxyLmhlYWRlcnM9VS5mcm9tKHIuaGVhZGVycykscn0sZnVuY3Rpb24ocil7cmV0dXJuIGxlKHIpfHwoZUEoZSksciYmci5yZXNwb25zZSYmKHIucmVzcG9uc2UuZGF0YT1JZS5jYWxsKGUsZS50cmFuc2Zvcm1SZXNwb25zZSxyLnJlc3BvbnNlKSxyLnJlc3BvbnNlLmhlYWRlcnM9VS5mcm9tKHIucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChyKX0pfXZhciBKdD1lPT5lIGluc3RhbmNlb2YgVT9lLnRvSlNPTigpOmU7ZnVuY3Rpb24gRyhlLEEpe0E9QXx8e307bGV0IHQ9e307ZnVuY3Rpb24gcihnLG4sdSl7cmV0dXJuIGMuaXNQbGFpbk9iamVjdChnKSYmYy5pc1BsYWluT2JqZWN0KG4pP2MubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6dX0sZyxuKTpjLmlzUGxhaW5PYmplY3Qobik/Yy5tZXJnZSh7fSxuKTpjLmlzQXJyYXkobik/bi5zbGljZSgpOm59ZnVuY3Rpb24gYShnLG4sdSl7aWYoYy5pc1VuZGVmaW5lZChuKSl7aWYoIWMuaXNVbmRlZmluZWQoZykpcmV0dXJuIHIodm9pZCAwLGcsdSl9ZWxzZSByZXR1cm4gcihnLG4sdSl9ZnVuY3Rpb24gbyhnLG4pe2lmKCFjLmlzVW5kZWZpbmVkKG4pKXJldHVybiByKHZvaWQgMCxuKX1mdW5jdGlvbiBpKGcsbil7aWYoYy5pc1VuZGVmaW5lZChuKSl7aWYoIWMuaXNVbmRlZmluZWQoZykpcmV0dXJuIHIodm9pZCAwLGcpfWVsc2UgcmV0dXJuIHIodm9pZCAwLG4pfWZ1bmN0aW9uIGwoZyxuLHUpe2lmKHUgaW4gQSlyZXR1cm4gcihnLG4pO2lmKHUgaW4gZSlyZXR1cm4gcih2b2lkIDAsZyl9bGV0IGY9e3VybDpvLG1ldGhvZDpvLGRhdGE6byxiYXNlVVJMOmksdHJhbnNmb3JtUmVxdWVzdDppLHRyYW5zZm9ybVJlc3BvbnNlOmkscGFyYW1zU2VyaWFsaXplcjppLHRpbWVvdXQ6aSx0aW1lb3V0TWVzc2FnZTppLHdpdGhDcmVkZW50aWFsczppLGFkYXB0ZXI6aSxyZXNwb25zZVR5cGU6aSx4c3JmQ29va2llTmFtZTppLHhzcmZIZWFkZXJOYW1lOmksb25VcGxvYWRQcm9ncmVzczppLG9uRG93bmxvYWRQcm9ncmVzczppLGRlY29tcHJlc3M6aSxtYXhDb250ZW50TGVuZ3RoOmksbWF4Qm9keUxlbmd0aDppLGJlZm9yZVJlZGlyZWN0OmksdHJhbnNwb3J0OmksaHR0cEFnZW50OmksaHR0cHNBZ2VudDppLGNhbmNlbFRva2VuOmksc29ja2V0UGF0aDppLHJlc3BvbnNlRW5jb2Rpbmc6aSx2YWxpZGF0ZVN0YXR1czpsLGhlYWRlcnM6KGcsbik9PmEoSnQoZyksSnQobiksITApfTtyZXR1cm4gYy5mb3JFYWNoKE9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30sZSxBKSksZnVuY3Rpb24obil7bGV0IHU9ZltuXXx8YSxwPXUoZVtuXSxBW25dLG4pO2MuaXNVbmRlZmluZWQocCkmJnUhPT1sfHwodFtuXT1wKX0pLHR9dmFyIGJlPSIxLjYuMCI7dmFyIEFBPXt9O1sib2JqZWN0IiwiYm9vbGVhbiIsIm51bWJlciIsImZ1bmN0aW9uIiwic3RyaW5nIiwic3ltYm9sIl0uZm9yRWFjaCgoZSxBKT0+e0FBW2VdPWZ1bmN0aW9uKHIpe3JldHVybiB0eXBlb2Ygcj09PWV8fCJhIisoQTwxPyJuICI6IiAiKStlfX0pO3ZhciBMdD17fTtBQS50cmFuc2l0aW9uYWw9ZnVuY3Rpb24oQSx0LHIpe2Z1bmN0aW9uIGEobyxpKXtyZXR1cm4iW0F4aW9zIHYiK2JlKyJdIFRyYW5zaXRpb25hbCBvcHRpb24gJyIrbysiJyIraSsocj8iLiAiK3I6IiIpfXJldHVybihvLGksbCk9PntpZihBPT09ITEpdGhyb3cgbmV3IGgoYShpLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKHQ/IiBpbiAiK3Q6IiIpKSxoLkVSUl9ERVBSRUNBVEVEKTtyZXR1cm4gdCYmIUx0W2ldJiYoTHRbaV09ITAsY29uc29sZS53YXJuKGEoaSwiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrdCsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSxBP0EobyxpLGwpOiEwfX07ZnVuY3Rpb24gRmkoZSxBLHQpe2lmKHR5cGVvZiBlIT0ib2JqZWN0Iil0aHJvdyBuZXcgaCgib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIsaC5FUlJfQkFEX09QVElPTl9WQUxVRSk7bGV0IHI9T2JqZWN0LmtleXMoZSksYT1yLmxlbmd0aDtmb3IoO2EtLSA+MDspe2xldCBvPXJbYV0saT1BW29dO2lmKGkpe2xldCBsPWVbb10sZj1sPT09dm9pZCAwfHxpKGwsbyxlKTtpZihmIT09ITApdGhyb3cgbmV3IGgoIm9wdGlvbiAiK28rIiBtdXN0IGJlICIrZixoLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgbmV3IGgoIlVua25vd24gb3B0aW9uICIrbyxoLkVSUl9CQURfT1BUSU9OKX19dmFyIGtlPXthc3NlcnRPcHRpb25zOkZpLHZhbGlkYXRvcnM6QUF9O3ZhciBNPWtlLnZhbGlkYXRvcnMsWj1jbGFzc3tjb25zdHJ1Y3RvcihBKXt0aGlzLmRlZmF1bHRzPUEsdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IHZlLHJlc3BvbnNlOm5ldyB2ZX19cmVxdWVzdChBLHQpe3R5cGVvZiBBPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1BKTp0PUF8fHt9LHQ9Ryh0aGlzLmRlZmF1bHRzLHQpO2xldHt0cmFuc2l0aW9uYWw6cixwYXJhbXNTZXJpYWxpemVyOmEsaGVhZGVyczpvfT10O3IhPT12b2lkIDAmJmtlLmFzc2VydE9wdGlvbnMocix7c2lsZW50SlNPTlBhcnNpbmc6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpNLnRyYW5zaXRpb25hbChNLmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKX0sITEpLGEhPW51bGwmJihjLmlzRnVuY3Rpb24oYSk/dC5wYXJhbXNTZXJpYWxpemVyPXtzZXJpYWxpemU6YX06a2UuYXNzZXJ0T3B0aW9ucyhhLHtlbmNvZGU6TS5mdW5jdGlvbixzZXJpYWxpemU6TS5mdW5jdGlvbn0sITApKSx0Lm1ldGhvZD0odC5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgaT1vJiZjLm1lcmdlKG8uY29tbW9uLG9bdC5tZXRob2RdKTtvJiZjLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sST0+e2RlbGV0ZSBvW0ldfSksdC5oZWFkZXJzPVUuY29uY2F0KGksbyk7bGV0IGw9W10sZj0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZCl7dHlwZW9mIGQucnVuV2hlbj09ImZ1bmN0aW9uIiYmZC5ydW5XaGVuKHQpPT09ITF8fChmPWYmJmQuc3luY2hyb25vdXMsbC51bnNoaWZ0KGQuZnVsZmlsbGVkLGQucmVqZWN0ZWQpKX0pO2xldCBnPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZCl7Zy5wdXNoKGQuZnVsZmlsbGVkLGQucmVqZWN0ZWQpfSk7bGV0IG4sdT0wLHA7aWYoIWYpe2xldCBJPVtSZS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKEkudW5zaGlmdC5hcHBseShJLGwpLEkucHVzaC5hcHBseShJLGcpLHA9SS5sZW5ndGgsbj1Qcm9taXNlLnJlc29sdmUodCk7dTxwOyluPW4udGhlbihJW3UrK10sSVt1KytdKTtyZXR1cm4gbn1wPWwubGVuZ3RoO2xldCBzPXQ7Zm9yKHU9MDt1PHA7KXtsZXQgST1sW3UrK10sZD1sW3UrK107dHJ5e3M9SShzKX1jYXRjaChFKXtkLmNhbGwodGhpcyxFKTticmVha319dHJ5e249UmUuY2FsbCh0aGlzLHMpfWNhdGNoKEkpe3JldHVybiBQcm9taXNlLnJlamVjdChJKX1mb3IodT0wLHA9Zy5sZW5ndGg7dTxwOyluPW4udGhlbihnW3UrK10sZ1t1KytdKTtyZXR1cm4gbn1nZXRVcmkoQSl7QT1HKHRoaXMuZGVmYXVsdHMsQSk7bGV0IHQ9Z2UoQS5iYXNlVVJMLEEudXJsKTtyZXR1cm4gbmUodCxBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpfX07Yy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihBKXtaLnByb3RvdHlwZVtBXT1mdW5jdGlvbih0LHIpe3JldHVybiB0aGlzLnJlcXVlc3QoRyhyfHx7fSx7bWV0aG9kOkEsdXJsOnQsZGF0YToocnx8e30pLmRhdGF9KSl9fSk7Yy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oQSl7ZnVuY3Rpb24gdChyKXtyZXR1cm4gZnVuY3Rpb24obyxpLGwpe3JldHVybiB0aGlzLnJlcXVlc3QoRyhsfHx7fSx7bWV0aG9kOkEsaGVhZGVyczpyP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDpvLGRhdGE6aX0pKX19Wi5wcm90b3R5cGVbQV09dCgpLFoucHJvdG90eXBlW0ErIkZvcm0iXT10KCEwKX0pO3ZhciBwZT1aO3ZhciB0QT1jbGFzcyBle2NvbnN0cnVjdG9yKEEpe2lmKHR5cGVvZiBBIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24obyl7dD1vfSk7bGV0IHI9dGhpczt0aGlzLnByb21pc2UudGhlbihhPT57aWYoIXIuX2xpc3RlbmVycylyZXR1cm47bGV0IG89ci5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO28tLSA+MDspci5fbGlzdGVuZXJzW29dKGEpO3IuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49YT0+e2xldCBvLGk9bmV3IFByb21pc2UobD0+e3Iuc3Vic2NyaWJlKGwpLG89bH0pLnRoZW4oYSk7cmV0dXJuIGkuY2FuY2VsPWZ1bmN0aW9uKCl7ci51bnN1YnNjcmliZShvKX0saX0sQShmdW5jdGlvbihvLGksbCl7ci5yZWFzb258fChyLnJlYXNvbj1uZXcgTChvLGksbCksdChyLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShBKXtpZih0aGlzLnJlYXNvbil7QSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChBKTp0aGlzLl9saXN0ZW5lcnM9W0FdfXVuc3Vic2NyaWJlKEEpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKEEpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgQTtyZXR1cm57dG9rZW46bmV3IGUoZnVuY3Rpb24oYSl7QT1hfSksY2FuY2VsOkF9fX0sTXQ9dEE7ZnVuY3Rpb24gckEoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBlLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGlBKGUpe3JldHVybiBjLmlzT2JqZWN0KGUpJiZlLmlzQXhpb3NFcnJvcj09PSEwfXZhciBhQT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXMoYUEpLmZvckVhY2goKFtlLEFdKT0+e2FBW0FdPWV9KTt2YXIgSHQ9YUE7ZnVuY3Rpb24gWXQoZSl7bGV0IEE9bmV3IHBlKGUpLHQ9aWUocGUucHJvdG90eXBlLnJlcXVlc3QsQSk7cmV0dXJuIGMuZXh0ZW5kKHQscGUucHJvdG90eXBlLEEse2FsbE93bktleXM6ITB9KSxjLmV4dGVuZCh0LEEsbnVsbCx7YWxsT3duS2V5czohMH0pLHQuY3JlYXRlPWZ1bmN0aW9uKGEpe3JldHVybiBZdChHKGUsYSkpfSx0fXZhciBiPVl0KHopO2IuQXhpb3M9cGU7Yi5DYW5jZWxlZEVycm9yPUw7Yi5DYW5jZWxUb2tlbj1NdDtiLmlzQ2FuY2VsPWxlO2IuVkVSU0lPTj1iZTtiLnRvRm9ybURhdGE9SjtiLkF4aW9zRXJyb3I9aDtiLkNhbmNlbD1iLkNhbmNlbGVkRXJyb3I7Yi5hbGw9ZnVuY3Rpb24oQSl7cmV0dXJuIFByb21pc2UuYWxsKEEpfTtiLnNwcmVhZD1yQTtiLmlzQXhpb3NFcnJvcj1pQTtiLm1lcmdlQ29uZmlnPUc7Yi5BeGlvc0hlYWRlcnM9VTtiLmZvcm1Ub0pTT049ZT0+UWUoYy5pc0hUTUxGb3JtKGUpP25ldyBGb3JtRGF0YShlKTplKTtiLmdldEFkYXB0ZXI9d2UuZ2V0QWRhcHRlcjtiLkh0dHBTdGF0dXNDb2RlPUh0O2IuZGVmYXVsdD1iO3ZhciBZPWI7dmFye0F4aW9zOnNJLEF4aW9zRXJyb3I6SUksQ2FuY2VsZWRFcnJvcjpsSSxpc0NhbmNlbDpnSSxDYW5jZWxUb2tlbjpwSSxWRVJTSU9OOm1JLGFsbDp1SSxDYW5jZWw6ZkksaXNBeGlvc0Vycm9yOmNJLHNwcmVhZDpkSSx0b0Zvcm1EYXRhOkJJLEF4aW9zSGVhZGVyczpDSSxIdHRwU3RhdHVzQ29kZTp5SSxmb3JtVG9KU09OOkVJLGdldEFkYXB0ZXI6UUksbWVyZ2VDb25maWc6aEl9PVk7dmFyIHZ0PVN5bWJvbCgiQ29tbGluay5wcm94eSIpLE9pPVN5bWJvbCgiQ29tbGluay5lbmRwb2ludCIpLHNBPVN5bWJvbCgiQ29tbGluay5yZWxlYXNlUHJveHkiKSxvQT1TeW1ib2woIkNvbWxpbmsuZmluYWxpemVyIiksRmU9U3ltYm9sKCJDb21saW5rLnRocm93biIpLEt0PWU9PnR5cGVvZiBlPT0ib2JqZWN0IiYmZSE9PW51bGx8fHR5cGVvZiBlPT0iZnVuY3Rpb24iLFVpPXtjYW5IYW5kbGU6ZT0+S3QoZSkmJmVbdnRdLHNlcmlhbGl6ZShlKXtsZXR7cG9ydDE6QSxwb3J0Mjp0fT1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIF90KGUsQSksW3QsW3RdXX0sZGVzZXJpYWxpemUoZSl7cmV0dXJuIGUuc3RhcnQoKSxJQShlKX19LFNpPXtjYW5IYW5kbGU6ZT0+S3QoZSkmJkZlIGluIGUsc2VyaWFsaXplKHt2YWx1ZTplfSl7bGV0IEE7cmV0dXJuIGUgaW5zdGFuY2VvZiBFcnJvcj9BPXtpc0Vycm9yOiEwLHZhbHVlOnttZXNzYWdlOmUubWVzc2FnZSxuYW1lOmUubmFtZSxzdGFjazplLnN0YWNrfX06QT17aXNFcnJvcjohMSx2YWx1ZTplfSxbQSxbXV19LGRlc2VyaWFsaXplKGUpe3Rocm93IGUuaXNFcnJvcj9PYmplY3QuYXNzaWduKG5ldyBFcnJvcihlLnZhbHVlLm1lc3NhZ2UpLGUudmFsdWUpOmUudmFsdWV9fSxqdD1uZXcgTWFwKFtbInByb3h5IixVaV0sWyJ0aHJvdyIsU2ldXSk7ZnVuY3Rpb24gV2koZSxBKXtmb3IobGV0IHQgb2YgZSlpZihBPT09dHx8dD09PSIqInx8dCBpbnN0YW5jZW9mIFJlZ0V4cCYmdC50ZXN0KEEpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIF90KGUsQT1nbG9iYWxUaGlzLHQ9WyIqIl0pe0EuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gcihhKXtpZighYXx8IWEuZGF0YSlyZXR1cm47aWYoIVdpKHQsYS5vcmlnaW4pKXtjb25zb2xlLndhcm4oYEludmFsaWQgb3JpZ2luICcke2Eub3JpZ2lufScgZm9yIGNvbWxpbmsgcHJveHlgKTtyZXR1cm59bGV0e2lkOm8sdHlwZTppLHBhdGg6bH09T2JqZWN0LmFzc2lnbih7cGF0aDpbXX0sYS5kYXRhKSxmPShhLmRhdGEuYXJndW1lbnRMaXN0fHxbXSkubWFwKHEpLGc7dHJ5e2xldCBuPWwuc2xpY2UoMCwtMSkucmVkdWNlKChwLHMpPT5wW3NdLGUpLHU9bC5yZWR1Y2UoKHAscyk9PnBbc10sZSk7c3dpdGNoKGkpe2Nhc2UiR0VUIjpnPXU7YnJlYWs7Y2FzZSJTRVQiOm5bbC5zbGljZSgtMSlbMF1dPXEoYS5kYXRhLnZhbHVlKSxnPSEwO2JyZWFrO2Nhc2UiQVBQTFkiOmc9dS5hcHBseShuLGYpO2JyZWFrO2Nhc2UiQ09OU1RSVUNUIjp7bGV0IHA9bmV3IHUoLi4uZik7Zz1UaShwKX1icmVhaztjYXNlIkVORFBPSU5UIjp7bGV0e3BvcnQxOnAscG9ydDI6c309bmV3IE1lc3NhZ2VDaGFubmVsO190KGUscyksZz1sQShwLFtwXSl9YnJlYWs7Y2FzZSJSRUxFQVNFIjpnPXZvaWQgMDticmVhaztkZWZhdWx0OnJldHVybn19Y2F0Y2gobil7Zz17dmFsdWU6bixbRmVdOjB9fVByb21pc2UucmVzb2x2ZShnKS5jYXRjaChuPT4oe3ZhbHVlOm4sW0ZlXTowfSkpLnRoZW4obj0+e2xldFt1LHBdPVNlKG4pO0EucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LHUpLHtpZDpvfSkscCksaT09PSJSRUxFQVNFIiYmKEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsciksenQoQSksb0EgaW4gZSYmdHlwZW9mIGVbb0FdPT0iZnVuY3Rpb24iJiZlW29BXSgpKX0pLmNhdGNoKG49PntsZXRbdSxwXT1TZSh7dmFsdWU6bmV3IFR5cGVFcnJvcigiVW5zZXJpYWxpemFibGUgcmV0dXJuIHZhbHVlIiksW0ZlXTowfSk7QS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sdSkse2lkOm99KSxwKX0pfSksQS5zdGFydCYmQS5zdGFydCgpfWZ1bmN0aW9uIE5pKGUpe3JldHVybiBlLmNvbnN0cnVjdG9yLm5hbWU9PT0iTWVzc2FnZVBvcnQifWZ1bmN0aW9uIHp0KGUpe05pKGUpJiZlLmNsb3NlKCl9ZnVuY3Rpb24gSUEoZSxBKXtyZXR1cm4gbkEoZSxbXSxBKX1mdW5jdGlvbiBEZShlKXtpZihlKXRocm93IG5ldyBFcnJvcigiUHJveHkgaGFzIGJlZW4gcmVsZWFzZWQgYW5kIGlzIG5vdCB1c2VhYmxlIil9ZnVuY3Rpb24gVnQoZSl7cmV0dXJuIFgoZSx7dHlwZToiUkVMRUFTRSJ9KS50aGVuKCgpPT57enQoZSl9KX12YXIgT2U9bmV3IFdlYWtNYXAsVWU9IkZpbmFsaXphdGlvblJlZ2lzdHJ5ImluIGdsb2JhbFRoaXMmJm5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeShlPT57bGV0IEE9KE9lLmdldChlKXx8MCktMTtPZS5zZXQoZSxBKSxBPT09MCYmVnQoZSl9KTtmdW5jdGlvbiBQaShlLEEpe2xldCB0PShPZS5nZXQoQSl8fDApKzE7T2Uuc2V0KEEsdCksVWUmJlVlLnJlZ2lzdGVyKGUsQSxlKX1mdW5jdGlvbiB4aShlKXtVZSYmVWUudW5yZWdpc3RlcihlKX1mdW5jdGlvbiBuQShlLEE9W10sdD1mdW5jdGlvbigpe30pe2xldCByPSExLGE9bmV3IFByb3h5KHQse2dldChvLGkpe2lmKERlKHIpLGk9PT1zQSlyZXR1cm4oKT0+e3hpKGEpLFZ0KGUpLHI9ITB9O2lmKGk9PT0idGhlbiIpe2lmKEEubGVuZ3RoPT09MClyZXR1cm57dGhlbjooKT0+YX07bGV0IGw9WChlLHt0eXBlOiJHRVQiLHBhdGg6QS5tYXAoZj0+Zi50b1N0cmluZygpKX0pLnRoZW4ocSk7cmV0dXJuIGwudGhlbi5iaW5kKGwpfXJldHVybiBuQShlLFsuLi5BLGldKX0sc2V0KG8saSxsKXtEZShyKTtsZXRbZixnXT1TZShsKTtyZXR1cm4gWChlLHt0eXBlOiJTRVQiLHBhdGg6Wy4uLkEsaV0ubWFwKG49Pm4udG9TdHJpbmcoKSksdmFsdWU6Zn0sZykudGhlbihxKX0sYXBwbHkobyxpLGwpe0RlKHIpO2xldCBmPUFbQS5sZW5ndGgtMV07aWYoZj09PU9pKXJldHVybiBYKGUse3R5cGU6IkVORFBPSU5UIn0pLnRoZW4ocSk7aWYoZj09PSJiaW5kIilyZXR1cm4gbkEoZSxBLnNsaWNlKDAsLTEpKTtsZXRbZyxuXT1xdChsKTtyZXR1cm4gWChlLHt0eXBlOiJBUFBMWSIscGF0aDpBLm1hcCh1PT51LnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpnfSxuKS50aGVuKHEpfSxjb25zdHJ1Y3QobyxpKXtEZShyKTtsZXRbbCxmXT1xdChpKTtyZXR1cm4gWChlLHt0eXBlOiJDT05TVFJVQ1QiLHBhdGg6QS5tYXAoZz0+Zy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6bH0sZikudGhlbihxKX19KTtyZXR1cm4gUGkoYSxlKSxhfWZ1bmN0aW9uIEdpKGUpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLGUpfWZ1bmN0aW9uIHF0KGUpe2xldCBBPWUubWFwKFNlKTtyZXR1cm5bQS5tYXAodD0+dFswXSksR2koQS5tYXAodD0+dFsxXSkpXX12YXIgWnQ9bmV3IFdlYWtNYXA7ZnVuY3Rpb24gbEEoZSxBKXtyZXR1cm4gWnQuc2V0KGUsQSksZX1mdW5jdGlvbiBUaShlKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihlLHtbdnRdOiEwfSl9ZnVuY3Rpb24gU2UoZSl7Zm9yKGxldFtBLHRdb2YganQpaWYodC5jYW5IYW5kbGUoZSkpe2xldFtyLGFdPXQuc2VyaWFsaXplKGUpO3JldHVyblt7dHlwZToiSEFORExFUiIsbmFtZTpBLHZhbHVlOnJ9LGFdfXJldHVyblt7dHlwZToiUkFXIix2YWx1ZTplfSxadC5nZXQoZSl8fFtdXX1mdW5jdGlvbiBxKGUpe3N3aXRjaChlLnR5cGUpe2Nhc2UiSEFORExFUiI6cmV0dXJuIGp0LmdldChlLm5hbWUpLmRlc2VyaWFsaXplKGUudmFsdWUpO2Nhc2UiUkFXIjpyZXR1cm4gZS52YWx1ZX19ZnVuY3Rpb24gWChlLEEsdCl7cmV0dXJuIG5ldyBQcm9taXNlKHI9PntsZXQgYT1KaSgpO2UuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gbyhpKXshaS5kYXRhfHwhaS5kYXRhLmlkfHxpLmRhdGEuaWQhPT1hfHwoZS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixvKSxyKGkuZGF0YSkpfSksZS5zdGFydCYmZS5zdGFydCgpLGUucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbih7aWQ6YX0sQSksdCl9KX1mdW5jdGlvbiBKaSgpe3JldHVybiBuZXcgQXJyYXkoNCkuZmlsbCgwKS5tYXAoKCk9Pk1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikudG9TdHJpbmcoMTYpKS5qb2luKCItIil9ZnVuY3Rpb24gJHQoZSl7bGV0IEE9SUEoZSksdD1lO3JldHVybiB0LndvcmtlclByb3h5PUEsdC5vcmlnaW5hbFRlcm1pbmF0ZT10LnRlcm1pbmF0ZSx0LnRlcm1pbmF0ZT0oKT0+e3Qud29ya2VyUHJveHlbc0FdKCksdC5vcmlnaW5hbFRlcm1pbmF0ZSgpfSx7d29ya2VyUHJveHk6QSx3b3JrZXI6dH19YXN5bmMgZnVuY3Rpb24gTGkoZSxBKXtsZXQgdDtpZihlIT1udWxsKXtsZXQgaT1lO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyh0PWkud29ya2VyUHJveHkse3dvcmtlclByb3h5OnQsd29ya2VyOml9KTokdChlKX1sZXQgcj10eXBlb2YgQT4idSI/di5waXBlbGluZVdvcmtlclVybDpBLGE9bnVsbCxvPXYud2ViV29ya2Vyc1VybDtpZih0eXBlb2YgbzwidSIpe2NvbnNvbGUud2FybigiaXRrQ29uZmlnIHdlYldvcmtlcnNVcmwgaXMgZGVwcmVjYXRlZC4gUGxlYXNlIHVzZSBwaXBlbGluZVdvcmtlclVybCB3aXRoIHRoZSBmdWxsIHBhdGggdG8gdGhlIHBpcGVsaW5lIHdvcmtlci4iKTtsZXQgaT0ibWluLiIsbD1vO2lmKGwuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgZj1hd2FpdCBZLmdldChgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHtyZXNwb25zZVR5cGU6ImJsb2IifSksZz1VUkwuY3JlYXRlT2JqZWN0VVJMKGYuZGF0YSk7YT1uZXcgV29ya2VyKGcse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIGE9bmV3IFdvcmtlcihgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBpZihyPT09bnVsbClhPW5ldyBXb3JrZXIobmV3IFVSTCgiLi93ZWItd29ya2Vycy9pdGstd2FzbS1waXBlbGluZS53b3JrZXIuanMiLGltcG9ydC5tZXRhLnVybCkse3R5cGU6Im1vZHVsZSJ9KTtlbHNlIGlmKHIuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgaT1hd2FpdCBZLmdldChyLHtyZXNwb25zZVR5cGU6ImJsb2IifSksbD1VUkwuY3JlYXRlT2JqZWN0VVJMKGkuZGF0YSk7YT1uZXcgV29ya2VyKGwse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIGE9bmV3IFdvcmtlcihyLHt0eXBlOiJtb2R1bGUifSk7cmV0dXJuICR0KGEpfXZhciBlcj1MaTt2YXIgTWk7ZnVuY3Rpb24gQXIoKXtyZXR1cm4gTWl9dmFyIEhpO2Z1bmN0aW9uIHRyKCl7cmV0dXJuIEhpfWZ1bmN0aW9uIFlpKGUpe2xldCBBPWUuc2xpY2UoKGUubGFzdEluZGV4T2YoIi4iKS0xPj4+MCkrMik7aWYoQS50b0xvd2VyQ2FzZSgpPT09Imd6Iil7bGV0IHQ9ZS5zbGljZSgwLC0zKS5sYXN0SW5kZXhPZigiLiIpO0E9ZS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihBLnRvTG93ZXJDYXNlKCk9PT0iY2JvciIpe2xldCB0PWUuc2xpY2UoMCwtNSkubGFzdEluZGV4T2YoIi4iKTtBPWUuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoQS50b0xvd2VyQ2FzZSgpPT09InpzdCIpe2xldCB0PWUuc2xpY2UoMCwtMTApLmxhc3RJbmRleE9mKCIuIik7QT1lLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKEEudG9Mb3dlckNhc2UoKT09PSJ6aXAiKXtsZXQgdD1lLnNsaWNlKDAsLTQpLmxhc3RJbmRleE9mKCIuIik7QT1lLnNsaWNlKCh0LTE+Pj4wKSsyKX1yZXR1cm4gQX12YXIgbWU9WWk7ZnVuY3Rpb24gcWkoZSl7cmV0dXJuW2UuZGF0YSxlLmRpcmVjdGlvbl19dmFyIGdBPXFpO2Z1bmN0aW9uIHZpKGUpe3JldHVybltlLnBvaW50cyxlLnBvaW50RGF0YSxlLmNlbGxzLGUuY2VsbERhdGFdfXZhciBycj12aTthc3luYyBmdW5jdGlvbiBLaShlLEEpe2xldCB0PSJ1bmtub3duIjt0eXBlb2YgZSE9InN0cmluZyI/dD1lLmhyZWY6ZS5zdGFydHNXaXRoKCJodHRwIik/dD1lOnQ9YCR7QX0vJHtlfWAsdC5lbmRzV2l0aCgiLmpzIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtMykpLHQuZW5kc1dpdGgoIi53YXNtIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtNSkpO2xldCByPWAke3R9Lndhc21gLG89KGF3YWl0IFkuZ2V0KHIse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIifSkpLmRhdGE7cmV0dXJuKGF3YWl0IGltcG9ydChgJHt0fS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5Om99KX12YXIgaXI9S2k7dmFyIGFyPWFzeW5jKCk9PldlYkFzc2VtYmx5LnZhbGlkYXRlKG5ldyBVaW50OEFycmF5KFswLDk3LDExNSwxMDksMSwwLDAsMCwxLDUsMSw5NiwwLDEsMTIzLDMsMiwxLDAsMTAsMTAsMSw4LDAsNjUsMCwyNTMsMTUsMjUzLDk4LDExXSkpO3ZhciBzcj10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixvcj1uZXcgVGV4dEVuY29kZXIsbnI9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoZSxBKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxyPWUuZnNfb3BlbihBLHQuZmxhZ3MpLG89ZS5mc19zdGF0KEEpLnNpemUsaT1udWxsO3NyP2k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKG8pOmk9bmV3IEFycmF5QnVmZmVyKG8pO2xldCBsPW5ldyBVaW50OEFycmF5KGkpO3JldHVybiBlLmZzX3JlYWQocixsLDAsbywwKSxlLmZzX2Nsb3NlKHIpLGx9ZnVuY3Rpb24gSXIoZSxBLHQpe2xldCByPW51bGw7c3I/cj1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6cj1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IGE9bmV3IFVpbnQ4QXJyYXkociksbz1uZXcgVWludDhBcnJheShlLkhFQVBVOC5idWZmZXIsQSx0KTtyZXR1cm4gYS5zZXQobyksYX1mdW5jdGlvbiBPKGUsQSx0LHIpe2xldCBhPTA7cmV0dXJuIEEhPT1udWxsJiYoYT1lLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LHIsQS5idWZmZXIuYnl0ZUxlbmd0aF0pLGUuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShBLmJ1ZmZlciksYSkpLGF9ZnVuY3Rpb24gJChlLEEsdCl7bGV0IHI9SlNPTi5zdHJpbmdpZnkoQSksYT1lLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsci5sZW5ndGhdKTtlLndyaXRlQXNjaWlUb01lbW9yeShyLGEsITEpfWZ1bmN0aW9uIE4oZSxBLHQscil7bGV0IGE9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQSx0XSksbz1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxBLHRdKSxpPUlyKGUsYSxvKTtyZXR1cm4gRChyLGkuYnVmZmVyKX1mdW5jdGlvbiBwQShlLEEpe2xldCB0PWUuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsQV0pLHI9ZS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKHIpfWZ1bmN0aW9uIGppKGUsQSx0LHIpe3IhPW51bGwmJnIubGVuZ3RoPjAmJnIuZm9yRWFjaChmdW5jdGlvbihnLG4pe3ZhciB1O3N3aXRjaChnLnR5cGUpe2Nhc2UgbS5UZXh0U3RyZWFtOntsZXQgcD1vci5lbmNvZGUoZy5kYXRhLmRhdGEpLHM9TyhlLHAsbiwwKSxJPXtzaXplOnAuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3N9YH07JChlLEksbik7YnJlYWt9Y2FzZSBtLkpzb25Db21wYXRpYmxlOntsZXQgcD1vci5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoZy5kYXRhKSkscz1PKGUscCxuLDApLEk9e3NpemU6cC5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7c31gfTskKGUsSSxuKTticmVha31jYXNlIG0uQmluYXJ5U3RyZWFtOntsZXQgcD1nLmRhdGEuZGF0YSxzPU8oZSxwLG4sMCksST17c2l6ZTpwLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWB9OyQoZSxJLG4pO2JyZWFrfWNhc2UgbS5UZXh0RmlsZTp7ZS5mc193cml0ZUZpbGUoZy5kYXRhLnBhdGgsZy5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgbS5CaW5hcnlGaWxlOntlLmZzX3dyaXRlRmlsZShnLmRhdGEucGF0aCxnLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBtLkltYWdlOntsZXQgcD1nLmRhdGEscz1PKGUscC5kYXRhLG4sMCksST1PKGUscC5kaXJlY3Rpb24sbiwxKSxkPXR5cGVvZigodT1wLm1ldGFkYXRhKT09PW51bGx8fHU9PT12b2lkIDA/dm9pZCAwOnUuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20ocC5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLEU9e2ltYWdlVHlwZTpwLmltYWdlVHlwZSxuYW1lOnAubmFtZSxvcmlnaW46cC5vcmlnaW4sc3BhY2luZzpwLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLHNpemU6cC5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWAsbWV0YWRhdGE6ZH07JChlLEUsbik7YnJlYWt9Y2FzZSBtLk1lc2g6e2xldCBwPWcuZGF0YSxzPU8oZSxwLnBvaW50cyxuLDApLEk9TyhlLHAuY2VsbHMsbiwxKSxkPU8oZSxwLnBvaW50RGF0YSxuLDIpLEU9TyhlLHAuY2VsbERhdGEsbiwzKSxSPXttZXNoVHlwZTpwLm1lc2hUeXBlLG5hbWU6cC5uYW1lLG51bWJlck9mUG9pbnRzOnAubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7c31gLG51bWJlck9mQ2VsbHM6cC5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLGNlbGxCdWZmZXJTaXplOnAuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpwLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7ZH1gLG51bWJlck9mQ2VsbFBpeGVsczpwLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YH07JChlLFIsbik7YnJlYWt9Y2FzZSBtLlBvbHlEYXRhOntsZXQgcD1nLmRhdGEscz1PKGUscC5wb2ludHMsbiwwKSxJPU8oZSxwLnZlcnRpY2VzLG4sMSksZD1PKGUscC5saW5lcyxuLDIpLEU9TyhlLHAucG9seWdvbnMsbiwzKSxSPU8oZSxwLnRyaWFuZ2xlU3RyaXBzLG4sNCksdz1PKGUscC5wb2ludERhdGEsbiw1KSxrPU8oZSxwLnBvaW50RGF0YSxuLDYpLFdlPXtwb2x5RGF0YVR5cGU6cC5wb2x5RGF0YVR5cGUsbmFtZTpwLm5hbWUsbnVtYmVyT2ZQb2ludHM6cC5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWAsdmVydGljZXNCdWZmZXJTaXplOnAudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLGxpbmVzQnVmZmVyU2l6ZTpwLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2R9YCxwb2x5Z29uc0J1ZmZlclNpemU6cC5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOnAudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Un1gLG51bWJlck9mUG9pbnRQaXhlbHM6cC5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3d9YCxudW1iZXJPZkNlbGxQaXhlbHM6cC5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtrfWB9OyQoZSxXZSxuKTticmVha31jYXNlIFcuVGV4dDp7ZS5mc193cml0ZUZpbGUoZy5wYXRoLGcuZGF0YSk7YnJlYWt9Y2FzZSBXLkJpbmFyeTp7ZS5mc193cml0ZUZpbGUoZy5wYXRoLGcuZGF0YSk7YnJlYWt9Y2FzZSBXLkltYWdlOntsZXQgcD1nLmRhdGEscz17aW1hZ2VUeXBlOnAuaW1hZ2VUeXBlLG5hbWU6cC5uYW1lLG9yaWdpbjpwLm9yaWdpbixzcGFjaW5nOnAuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTpwLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKGUuZnNfbWtkaXJzKGAke2cucGF0aH0vZGF0YWApLGUuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkocykpLHAuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkocC5kYXRhLmJ1ZmZlcikpLGUuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShwLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFcuTWVzaDp7bGV0IHA9Zy5kYXRhLHM9e21lc2hUeXBlOnAubWVzaFR5cGUsbmFtZTpwLm5hbWUsbnVtYmVyT2ZQb2ludHM6cC5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczpwLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6cC5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOnAubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6cC5jZWxsQnVmZmVyU2l6ZX07aWYoZS5mc19ta2RpcnMoYCR7Zy5wYXRofS9kYXRhYCksZS5mc193cml0ZUZpbGUoYCR7Zy5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShzKSkscy5udW1iZXJPZlBvaW50cz4wKXtpZihwLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtlLmZzX3dyaXRlRmlsZShgJHtnLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkocC5wb2ludHMuYnVmZmVyKSl9aWYocy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKHAucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShwLnBvaW50RGF0YS5idWZmZXIpKX1pZihzLm51bWJlck9mQ2VsbHM+MCl7aWYocC5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KHAuY2VsbHMuYnVmZmVyKSl9aWYocy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYocC5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KHAuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLGUucmVzZXRNb2R1bGVTdGRvdXQoKSxlLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IGE9ZS5zdGFja1NhdmUoKSxvPTA7dHJ5e289ZS5jYWxsTWFpbihBLnNsaWNlKCkpfWNhdGNoKGcpe3Rocm93IHR5cGVvZiBnPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsZS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsZS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIGUuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsZS5nZXRFeGNlcHRpb25NZXNzYWdlKGcpKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLGd9ZmluYWxseXtlLnN0YWNrUmVzdG9yZShhKX1sZXQgaT1lLmdldE1vZHVsZVN0ZG91dCgpLGw9ZS5nZXRNb2R1bGVTdGRlcnIoKSxmPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZvPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKGcsbil7bGV0IHU9bnVsbDtzd2l0Y2goZy50eXBlKXtjYXNlIG0uVGV4dFN0cmVhbTp7bGV0IHM9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbiwwXSksST1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxuLDBdKSxkPW5ldyBVaW50OEFycmF5KGUuSEVBUFU4LmJ1ZmZlcixzLEkpO3U9e2RhdGE6bnIuZGVjb2RlKGQpfTticmVha31jYXNlIG0uSnNvbkNvbXBhdGlibGU6e2xldCBzPWUuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG4sMF0pLEk9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbiwwXSksZD1uZXcgVWludDhBcnJheShlLkhFQVBVOC5idWZmZXIscyxJKTt1PUpTT04ucGFyc2UobnIuZGVjb2RlKGQpKTticmVha31jYXNlIG0uQmluYXJ5U3RyZWFtOntsZXQgcz1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxuLDBdKSxJPWUuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG4sMF0pO3U9e2RhdGE6SXIoZSxzLEkpfTticmVha31jYXNlIG0uVGV4dEZpbGU6e3U9e3BhdGg6Zy5kYXRhLnBhdGgsZGF0YTplLmZzX3JlYWRGaWxlKGcuZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSBtLkJpbmFyeUZpbGU6e3U9e3BhdGg6Zy5kYXRhLnBhdGgsZGF0YTpIKGUsZy5kYXRhLnBhdGgpfTticmVha31jYXNlIG0uSW1hZ2U6e2xldCBzPXBBKGUsbik7cy5kYXRhPU4oZSxuLDAscy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSkscy5kaXJlY3Rpb249TihlLG4sMSxTLkZsb2F0NjQpLHMubWV0YWRhdGE9bmV3IE1hcChzLm1ldGFkYXRhKSx1PXM7YnJlYWt9Y2FzZSBtLk1lc2g6e2xldCBzPXBBKGUsbik7cy5udW1iZXJPZlBvaW50cz4wP3MucG9pbnRzPU4oZSxuLDAscy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOnMucG9pbnRzPUQocy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzLm51bWJlck9mQ2VsbHM+MD9zLmNlbGxzPU4oZSxuLDEscy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6cy5jZWxscz1EKHMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzLm51bWJlck9mUG9pbnRQaXhlbHM+MD9zLnBvaW50RGF0YT1OKGUsbiwyLHMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOnMucG9pbnREYXRhPUQocy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/cy5jZWxsRGF0YT1OKGUsbiwzLHMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6cy5jZWxsRGF0YT1EKHMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHU9czticmVha31jYXNlIG0uUG9seURhdGE6e2xldCBzPXBBKGUsbik7cy5udW1iZXJPZlBvaW50cz4wP3MucG9pbnRzPU4oZSxuLDAsUy5GbG9hdDMyKTpzLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LHMudmVydGljZXNCdWZmZXJTaXplPjA/cy52ZXJ0aWNlcz1OKGUsbiwxLFEuVUludDMyKTpzLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxzLmxpbmVzQnVmZmVyU2l6ZT4wP3MubGluZXM9TihlLG4sMixRLlVJbnQzMik6cy5saW5lcz1uZXcgVWludDMyQXJyYXkscy5wb2x5Z29uc0J1ZmZlclNpemU+MD9zLnBvbHlnb25zPU4oZSxuLDMsUS5VSW50MzIpOnMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LHMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/cy50cmlhbmdsZVN0cmlwcz1OKGUsbiw0LFEuVUludDMyKTpzLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxzLm51bWJlck9mUG9pbnRQaXhlbHM+MD9zLnBvaW50RGF0YT1OKGUsbiw1LHMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpzLnBvaW50RGF0YT1EKHMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSkscy5udW1iZXJPZkNlbGxQaXhlbHM+MD9zLmNlbGxEYXRhPU4oZSxuLDYscy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6cy5jZWxsRGF0YT1EKHMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSx1PXM7YnJlYWt9Y2FzZSBXLlRleHQ6e2lmKHR5cGVvZiBnLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTt1PWUuZnNfcmVhZEZpbGUoZy5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFcuQmluYXJ5OntpZih0eXBlb2YgZy5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7dT1IKGUsZy5wYXRoKTticmVha31jYXNlIFcuSW1hZ2U6e2lmKHR5cGVvZiBnLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgcz1lLmZzX3JlYWRGaWxlKGAke2cucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLEk9SlNPTi5wYXJzZShzKSxkPUgoZSxgJHtnLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtJLmRhdGE9RChJLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGQuYnVmZmVyKTtsZXQgRT1IKGUsYCR7Zy5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtJLmRpcmVjdGlvbj1EKFMuRmxvYXQ2NCxFLmJ1ZmZlciksdT1JO2JyZWFrfWNhc2UgVy5NZXNoOntpZih0eXBlb2YgZy5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IHM9ZS5mc19yZWFkRmlsZShgJHtnLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxJPUpTT04ucGFyc2Uocyk7aWYoSS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZD1IKGUsYCR7Zy5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtJLnBvaW50cz1EKEkubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkucG9pbnRzPUQoSS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihJLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGQ9SChlLGAke2cucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7SS5wb2ludERhdGE9RChJLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkucG9pbnREYXRhPUQoSS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKEkubnVtYmVyT2ZDZWxscz4wKXtsZXQgZD1IKGUsYCR7Zy5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO0kuY2VsbHM9RChJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkuY2VsbHM9RChJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoSS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGQ9SChlLGAke2cucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtJLmNlbGxEYXRhPUQoSS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkuY2VsbERhdGE9RChJLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTt1PUk7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgcD17dHlwZTpnLnR5cGUsZGF0YTp1fTtmLnB1c2gocCl9KSx7cmV0dXJuVmFsdWU6byxzdGRvdXQ6aSxzdGRlcnI6bCxvdXRwdXRzOmZ9fXZhciBscj1qaTt2YXIgbUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiBfaShlKXtsZXQgQT1lLHQ9ZTtpZih0eXBlb2YgZSE9InN0cmluZyImJihBPW5ldyBVUkwoZS5ocmVmKSx0PUEuaHJlZiksbUEuaGFzKHQpKXJldHVybiBtQS5nZXQodCk7e2xldCByPWF3YWl0IGlyKGUsdi5waXBlbGluZXNVcmwpO3JldHVybiBtQS5zZXQodCxyKSxyfX1hc3luYyBmdW5jdGlvbiB6aShlLEEsdCxyLGEsbyl7dmFyIGksbDtpZighYXdhaXQgYXIoKSl7bGV0IHc9IldlYkFzc2VtYmx5IFNJTUQgc3VwcG9ydCBpcyByZXF1aXJlZCAtLSBwbGVhc2UgdXBkYXRlIHlvdXIgYnJvd3Nlci4iO3Rocm93IGFsZXJ0KHcpLG5ldyBFcnJvcih3KX1pZihlPT09ITEpe2xldCB3PWF3YWl0IF9pKEEudG9TdHJpbmcoKSk7cmV0dXJuIGxyKHcsdCxyLGEpfWxldCBmPWUsZz0oaT1vPy5waXBlbGluZVdvcmtlclVybCkhPT1udWxsJiZpIT09dm9pZCAwP2k6bnVsbCxuPXR5cGVvZiBnIT0ic3RyaW5nIiYmdHlwZW9mIGc/LmhyZWY8InUiP2cuaHJlZjpnLHt3b3JrZXJQcm94eTp1LHdvcmtlcjpwfT1hd2FpdCBlcihmLG4pO2Y9cDtsZXQgcz1bXTthIT1udWxsJiZhLmxlbmd0aD4wJiZhLmZvckVhY2goZnVuY3Rpb24odyl7aWYody50eXBlPT09bS5CaW5hcnlTdHJlYW0pe2xldCBrPXcuZGF0YS5kYXRhO3MucHVzaChrKX1lbHNlIGlmKHcudHlwZT09PW0uQmluYXJ5RmlsZSl7bGV0IGs9dy5kYXRhLmRhdGE7cy5wdXNoKGspfWVsc2UgaWYody50eXBlPT09bS5JbWFnZSl7bGV0IGs9dy5kYXRhO2lmKGsuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlIGRhdGEgY2Fubm90IGJlIG51bGwiKTtzLnB1c2goLi4uZ0EoaykpfWVsc2UgaWYody50eXBlPT09Vy5CaW5hcnkpcy5wdXNoKHcuZGF0YSk7ZWxzZSBpZih3LnR5cGU9PT1XLkltYWdlKXtsZXQgaz13LmRhdGE7aWYoay5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UgZGF0YSBjYW5ub3QgYmUgbnVsbCIpO3MucHVzaCguLi5nQShrKSl9ZWxzZSBpZih3LnR5cGU9PT1XLk1lc2gpe2xldCBrPXcuZGF0YTtzLnB1c2goLi4ucnIoaykpfX0pO2xldCBJPShsPW8/LnBpcGVsaW5lQmFzZVVybCkhPT1udWxsJiZsIT09dm9pZCAwP2w6InBpcGVsaW5lc1VybCIsZD10eXBlb2YgSSE9InN0cmluZyImJnR5cGVvZiBJPy5ocmVmPCJ1Ij9JLmhyZWY6SSxFPWEhPW51bGw/bEEoYSxsdChzKSk6bnVsbCxSPWF3YWl0IHUucnVuUGlwZWxpbmUodixBLnRvU3RyaW5nKCksZCx0LHIsRSk7cmV0dXJue3JldHVyblZhbHVlOlIucmV0dXJuVmFsdWUsc3Rkb3V0OlIuc3Rkb3V0LHN0ZGVycjpSLnN0ZGVycixvdXRwdXRzOlIub3V0cHV0cyx3ZWJXb3JrZXI6Zn19dmFyIEI9emk7dmFyIGdyPXtuYW1lOiJAaXRrLXdhc20vaW1hZ2UtaW8iLHZlcnNpb246IjAuNC4wIixkZXNjcmlwdGlvbjoiSW5wdXQgYW5kIG91dHB1dCBmb3Igc2NpZW50aWZpYyBhbmQgbWVkaWNhbCBpbWFnZSBmaWxlIGZvcm1hdHMuIix0eXBlOiJtb2R1bGUiLG1vZHVsZToiLi9kaXN0L2luZGV4LmpzIix0eXBlczoiLi9kaXN0L2luZGV4LmQudHMiLGV4cG9ydHM6eyIuIjp7dHlwZXM6Ii4vZGlzdC9pbmRleC5kLmpzIixicm93c2VyOiIuL2Rpc3QvaW5kZXguanMiLG5vZGU6Ii4vZGlzdC9pbmRleC1ub2RlLmpzIixkZWZhdWx0OiIuL2Rpc3QvaW5kZXguanMifX0sc2NyaXB0czp7c3RhcnQ6Im5wbSBydW4gY29weVNob2VsYWNlQXNzZXRzICYmIHZpdGUgLWMgYnVpbGQvdml0ZS5jb25maWcuanMiLHRlc3Q6Im5wbSBydW4gdGVzdDpub2RlICYmIG5wbSBydW4gdGVzdDpicm93c2VyIiwidGVzdDpub2RlIjoiYXZhIiwidGVzdDpicm93c2VyIjoibnBtIHJ1biB0ZXN0OmJyb3dzZXI6Y2hyb21lICYmIG5wbSBydW4gdGVzdDpicm93c2VyOmZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6ZmlyZWZveCI6InN0YXJ0LXNlcnZlci1hbmQtdGVzdCByb2xsdXA6c3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTAwNCBjeXByZXNzOnJ1bkZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6Y2hyb21lIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHJvbGx1cDpzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MDA0IGN5cHJlc3M6cnVuQ2hyb21lIiwidGVzdDpicm93c2VyOmRlYnVnIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHJvbGx1cDpzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MDA0IGN5cHJlc3M6b3BlbiIsImN5cHJlc3M6b3BlbiI6Im5weCBjeXByZXNzIG9wZW4iLCJjeXByZXNzOnJ1bkNocm9tZSI6Im5weCBjeXByZXNzIHJ1biAtLWJyb3dzZXIgY2hyb21lIiwiY3lwcmVzczpydW5GaXJlZm94IjoibnB4IGN5cHJlc3MgcnVuIC0tYnJvd3NlciBmaXJlZm94IixidWlsZDoibnBtIHJ1biBidWlsZDp0c2MgJiYgbnBtIHJ1biBidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkICYmIG5wbSBydW4gYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZE1pbiAmJiBucG0gcnVuIGJ1aWxkOmRlbW8iLCJidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkIjoiZXNidWlsZCAtLWxvYWRlcjoud29ya2VyLmpzPWRhdGF1cmwgLS1idW5kbGUgLS1mb3JtYXQ9ZXNtIC0tb3V0ZmlsZT0uL2Rpc3QvaW1hZ2UtaW8td29ya2VyLWVtYmVkZGVkLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC50cyIsImJ1aWxkOmJyb3dzZXI6d29ya2VyRW1iZWRkZWRNaW4iOiJlc2J1aWxkIC0tbWluaWZ5IC0tbG9hZGVyOi53b3JrZXIuanM9ZGF0YXVybCAtLWJ1bmRsZSAtLWZvcm1hdD1lc20gLS1vdXRmaWxlPS4vZGlzdC9pbWFnZS1pby13b3JrZXItZW1iZWRkZWQubWluLmpzIC4vc3JjL2luZGV4LXdvcmtlci1lbWJlZGRlZC1taW4udHMiLCJidWlsZDp0c2MiOiJ0c2MgLS1wcmV0dHkiLGNvcHlTaG9lbGFjZUFzc2V0czoic2h4IG1rZGlyIC1wIHRlc3QvYnJvd3Nlci9kZW1vLWFwcC9wdWJsaWMgJiYgc2h4IGNwIC1yIG5vZGVfbW9kdWxlcy9Ac2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UvZGlzdC9hc3NldHMgdGVzdC9icm93c2VyL2RlbW8tYXBwL3B1YmxpYy8iLCJidWlsZDpkZW1vIjoibnBtIHJ1biBjb3B5U2hvZWxhY2VBc3NldHMgJiYgdml0ZSAtYyBidWlsZC92aXRlLmNvbmZpZy5qcyBidWlsZCIsInJvbGx1cDpzdGFydCI6Im5wbSBydW4gY29weVNob2VsYWNlQXNzZXRzICYmIGNvbmN1cnJlbnRseSBucG06cm9sbHVwOmRldiBucG06cm9sbHVwOnByZXZpZXciLCJyb2xsdXA6ZGV2Ijoidml0ZSBidWlsZCAtLWNvbmZpZyBidWlsZC92aXRlLXJvbGx1cC13YXRjaC5jb25maWcudHMiLCJyb2xsdXA6cHJldmlldyI6InZpdGUgcHJldmlldyAtLWNvbmZpZyBidWlsZC92aXRlLXJvbGx1cC13YXRjaC5jb25maWcudHMifSxrZXl3b3JkczpbIml0ayIsIndhc20iLCJ3ZWJhc3NlbWJseSIsIndhc2kiXSxhdXRob3I6IiIsbGljZW5zZToiQXBhY2hlLTIuMCIsZGVwZW5kZW5jaWVzOnsiaXRrLXdhc20iOiJeMS4wLjAtYi4xNTQifSxkZXZEZXBlbmRlbmNpZXM6eyJAc2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UiOiJeMi41LjIiLCJAdHlwZXMvbm9kZSI6Il4yMC4yLjUiLGF2YToiXjUuMy4xIixjb25jdXJyZW50bHk6Il44LjIuMSIsY3lwcmVzczoiXjEzLjMuMCIsZXNidWlsZDoiXjAuMTkuNSIsc2h4OiJeMC4zLjQiLCJzdGFydC1zZXJ2ZXItYW5kLXRlc3QiOiJeMi4wLjEiLHR5cGVzY3JpcHQ6Il41LjAuNCIsdml0ZToiXjQuNS4wIiwidml0ZS1wbHVnaW4tc3RhdGljLWNvcHkiOiJeMC4xNy4wIn0scmVwb3NpdG9yeTp7dHlwZToiZ2l0Iix1cmw6Imh0dHBzOi8vZ2l0aHViLmNvbS9JbnNpZ2h0U29mdHdhcmVDb25zb3J0aXVtL2l0ay13YXNtIn0sYXZhOntmaWxlczpbInRlc3Qvbm9kZS8qKi8qIiwiIXRlc3Qvbm9kZS9jb21tb24uanMiXX19O3ZhciB1QSxaaT1gaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AaXRrLXdhc20vaW1hZ2UtaW9AJHtnci52ZXJzaW9ufS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gcGwoZSl7dUE9ZX1mdW5jdGlvbiBDKCl7aWYodHlwZW9mIHVBPCJ1IilyZXR1cm4gdUE7bGV0IGU9dHIoKTtyZXR1cm4gdHlwZW9mIGU8InUiP2U6Wml9dmFyIGZBLFhpPW51bGw7ZnVuY3Rpb24gcHIoZSl7ZkE9ZX1mdW5jdGlvbiB5KCl7aWYodHlwZW9mIGZBPCJ1IilyZXR1cm4gZkE7bGV0IGU9QXIoKTtyZXR1cm4gdHlwZW9mIGU8InUiP2U6WGl9dmFyICRpPW5ldyBNYXAoW1siaW1hZ2UvanBlZyIsImpwZWciXSxbImltYWdlL3BuZyIsInBuZyJdLFsiaW1hZ2UvdGlmZiIsInRpZmYiXSxbImltYWdlL3gtbXMtYm1wIiwiYm1wIl0sWyJpbWFnZS94LWJtcCIsImJtcCJdLFsiaW1hZ2UvYm1wIiwiYm1wIl0sWyJhcHBsaWNhdGlvbi9kaWNvbSIsImdkY20iXV0pLGVlPSRpO3ZhciBlYT1uZXcgTWFwKFtbImJtcCIsImJtcCJdLFsiZGNtIiwiZ2RjbSJdLFsiZ2lwbCIsImdpcGwiXSxbImdpcGwuZ3oiLCJnaXBsIl0sWyJoZGY1IiwiaGRmNSJdLFsianBnIiwianBlZyJdLFsianBlZyIsImpwZWciXSxbIml3aSIsIndhc20iXSxbIml3aS5jYm9yIiwid2FzbSJdLFsiaXdpLmNib3IuenN0Iiwid2FzbVpzdGQiXSxbImxzbSIsImxzbSJdLFsibW5jIiwibW5jIl0sWyJtbmMuZ3oiLCJtbmMiXSxbIm1uYzIiLCJtbmMiXSxbIm1naCIsIm1naCJdLFsibWd6IiwibWdoIl0sWyJtZ2guZ3oiLCJtZ2giXSxbIm1oYSIsIm1ldGEiXSxbIm1oZCIsIm1ldGEiXSxbIm1yYyIsIm1yYyJdLFsibmlhIiwibmlmdGkiXSxbIm5paSIsIm5pZnRpIl0sWyJuaWkuZ3oiLCJuaWZ0aSJdLFsiaGRyIiwibmlmdGkiXSxbIm5ycmQiLCJucnJkIl0sWyJuaGRyIiwibnJyZCJdLFsicG5nIiwicG5nIl0sWyJwaWMiLCJiaW9SYWQiXSxbInRpZiIsInRpZmYiXSxbInRpZmYiLCJ0aWZmIl0sWyJ2dGsiLCJ2dGsiXSxbImlzcSIsInNjYW5jbyJdLFsiYWltIiwic2NhbmNvIl0sWyJmZGYiLCJmZGYiXV0pLEFlPWVhO2FzeW5jIGZ1bmN0aW9uIEFhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0icG5nLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBjQT1BYTthc3luYyBmdW5jdGlvbiB0YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InBuZy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgZEE9dGE7YXN5bmMgZnVuY3Rpb24gcmEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJtZXRhLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBCQT1yYTthc3luYyBmdW5jdGlvbiBpYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1ldGEtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIENBPWlhO2FzeW5jIGZ1bmN0aW9uIGFhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0idGlmZi1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgeUE9YWE7YXN5bmMgZnVuY3Rpb24gb2EoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ0aWZmLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBFQT1vYTthc3luYyBmdW5jdGlvbiBuYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Im5pZnRpLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBRQT1uYTthc3luYyBmdW5jdGlvbiBzYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im5pZnRpLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBoQT1zYTthc3luYyBmdW5jdGlvbiBJYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImpwZWctcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHdBPUlhO2FzeW5jIGZ1bmN0aW9uIGxhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0ianBlZy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgUkE9bGE7YXN5bmMgZnVuY3Rpb24gZ2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJucnJkLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBiQT1nYTthc3luYyBmdW5jdGlvbiBwYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im5ycmQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIGtBPXBhO2FzeW5jIGZ1bmN0aW9uIG1hKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0idnRrLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBEQT1tYTthc3luYyBmdW5jdGlvbiB1YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InZ0ay13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgRkE9dWE7YXN5bmMgZnVuY3Rpb24gZmEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJibXAtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIE9BPWZhO2FzeW5jIGZ1bmN0aW9uIGNhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iYm1wLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBVQT1jYTthc3luYyBmdW5jdGlvbiBkYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImhkZjUtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIFNBPWRhO2FzeW5jIGZ1bmN0aW9uIEJhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iaGRmNS13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgV0E9QmE7YXN5bmMgZnVuY3Rpb24gQ2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJtaW5jLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBOQT1DYTthc3luYyBmdW5jdGlvbiB5YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1pbmMtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIFBBPXlhO2FzeW5jIGZ1bmN0aW9uIEVhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0ibXJjLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciB4QT1FYTthc3luYyBmdW5jdGlvbiBRYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1yYy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgR0E9UWE7YXN5bmMgZnVuY3Rpb24gaGEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJsc20tcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIFRBPWhhO2FzeW5jIGZ1bmN0aW9uIHdhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0ibHNtLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBKQT13YTthc3luYyBmdW5jdGlvbiBSYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Im1naC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgTEE9UmE7YXN5bmMgZnVuY3Rpb24gYmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJtZ2gtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIE1BPWJhO2FzeW5jIGZ1bmN0aW9uIGthKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0iYmlvLXJhZC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgSEE9a2E7YXN5bmMgZnVuY3Rpb24gRGEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJiaW8tcmFkLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBZQT1EYTthc3luYyBmdW5jdGlvbiBGYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImdpcGwtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHFBPUZhO2FzeW5jIGZ1bmN0aW9uIE9hKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iZ2lwbC13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgdkE9T2E7YXN5bmMgZnVuY3Rpb24gVWEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJnZS1hZHctcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIEtBPVVhO2FzeW5jIGZ1bmN0aW9uIFNhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iZ2UtYWR3LXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBqQT1TYTthc3luYyBmdW5jdGlvbiBXYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImdlNC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgX0E9V2E7YXN5bmMgZnVuY3Rpb24gTmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJnZTQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIHpBPU5hO2FzeW5jIGZ1bmN0aW9uIFBhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0iZ2U1LXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBWQT1QYTthc3luYyBmdW5jdGlvbiB4YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49ImdlNS13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgWkE9eGE7YXN5bmMgZnVuY3Rpb24gR2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJnZGNtLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBYQT1HYTthc3luYyBmdW5jdGlvbiBUYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49ImdkY20td3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyICRBPVRhO2FzeW5jIGZ1bmN0aW9uIEphKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0ic2NhbmNvLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBldD1KYTthc3luYyBmdW5jdGlvbiBMYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InNjYW5jby13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgQXQ9TGE7YXN5bmMgZnVuY3Rpb24gTWEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJmZGYtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHR0PU1hO2FzeW5jIGZ1bmN0aW9uIEhhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0id2FzbS1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgcnQ9SGE7YXN5bmMgZnVuY3Rpb24gWWEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ3YXNtLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBpdD1ZYTthc3luYyBmdW5jdGlvbiBxYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Indhc20tenN0ZC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgYXQ9cWE7YXN5bmMgZnVuY3Rpb24gdmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ3YXNtLXpzdGQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIG90PXZhO3ZhciBLYT1uZXcgTWFwKFtbInBuZyIsW2NBLGRBXV0sWyJtZXRhIixbQkEsQ0FdXSxbInRpZmYiLFt5QSxFQV1dLFsibmlmdGkiLFtRQSxoQV1dLFsianBlZyIsW3dBLFJBXV0sWyJucnJkIixbYkEsa0FdXSxbInZ0ayIsW0RBLEZBXV0sWyJibXAiLFtPQSxVQV1dLFsiaGRmNSIsW1NBLFdBXV0sWyJtaW5jIixbTkEsUEFdXSxbIm1yYyIsW3hBLEdBXV0sWyJsc20iLFtUQSxKQV1dLFsibWdoIixbTEEsTUFdXSxbImJpb1JhZCIsW0hBLFlBXV0sWyJnaXBsIixbcUEsdkFdXSxbImdlQWR3IixbS0EsakFdXSxbImdlNCIsW19BLHpBXV0sWyJnZTUiLFtWQSxaQV1dLFsiZ2RjbSIsW1hBLCRBXV0sWyJzY2FuY28iLFtldCxBdF1dLFsiZmRmIixbdHQsbnVsbF1dLFsid2FzbSIsW3J0LGl0XV0sWyJ3YXNtWnN0ZCIsW2F0LG90XV1dKSx0ZT1LYTthc3luYyBmdW5jdGlvbiBqYShlLEEsdD17fSl7bGV0IHI9QS50eXBlPz8iIixhPUEubmFtZT8/QS5wYXRoPz8iZmlsZU5hbWUiLG89bWUoYSkudG9Mb3dlckNhc2UoKSxpPWUsbD1BO2lmKEEgaW5zdGFuY2VvZiBCbG9iKXtsZXQgST1hd2FpdCBBLmFycmF5QnVmZmVyKCk7bD17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShJKX19bGV0IGY9bnVsbDtpZihyJiZlZS5oYXMocikpZj1lZS5nZXQocik7ZWxzZSBpZihBZS5oYXMobykpZj1BZS5nZXQobyk7ZWxzZSBmb3IobGV0IEkgb2YgdGUudmFsdWVzKCkpaWYoSVswXSE9PW51bGwpe2xldHt3ZWJXb3JrZXI6ZCxjb3VsZFJlYWQ6RSxpbWFnZTpSfT1hd2FpdCBJWzBdKGkse3BhdGg6bC5wYXRoLGRhdGE6bC5kYXRhLnNsaWNlKCl9LHtpbmZvcm1hdGlvbk9ubHk6dC5pbmZvcm1hdGlvbk9ubHl9KTtpZihpPWQsRSlyZXR1cm4gdHlwZW9mIHQ8InUiJiYoUj1UKFIsdCkpLHt3ZWJXb3JrZXI6aSxpbWFnZTpSfX1pZighZil0aHJvdyBFcnJvcigiQ291bGQgbm90IGZpbmQgSU8gZm9yOiAiK2EpO2xldCBuPXRlLmdldChmKVswXSx7d2ViV29ya2VyOnUsY291bGRSZWFkOnAsaW1hZ2U6c309YXdhaXQgbihpLGwse2luZm9ybWF0aW9uT25seTp0LmluZm9ybWF0aW9uT25seX0pO2lmKGk9dSwhcCl0aHJvdyBFcnJvcigiQ291bGQgbm90IHJlYWQ6ICIrYSk7cmV0dXJuIHR5cGVvZiB0PCJ1IiYmKHM9VChzLHQpKSx7d2ViV29ya2VyOmksaW1hZ2U6c319dmFyIG50PWphO3ZhciBfYT10eXBlb2YgZ2xvYmFsVGhpcy5uYXZpZ2F0b3I/LmhhcmR3YXJlQ29uY3VycmVuY3k9PSJudW1iZXIiP2dsb2JhbFRoaXMubmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3k6Nixtcj1uZXcgSmUoX2EsbnQpO2FzeW5jIGZ1bmN0aW9uIHphKGUsQSl7bGV0IHQ9MSxyPTAsYT0hMTt0eXBlb2YgQT09Im9iamVjdCImJih0eXBlb2YgQS56U3BhY2luZzwidSImJih0PUEuelNwYWNpbmcpLHR5cGVvZiBBLnpPcmlnaW48InUiJiYocj1BLnpPcmlnaW4pLHR5cGVvZiBBLnNvcnRlZFNlcmllczwidSImJihhPUEuc29ydGVkU2VyaWVzKSk7bGV0IG89QXJyYXkuZnJvbShlLGFzeW5jIGZ1bmN0aW9uKHUpe3JldHVybiBhd2FpdCB1LmFycmF5QnVmZmVyKCkudGhlbihmdW5jdGlvbihwKXtyZXR1cm57bmFtZTp1Lm5hbWUsdHlwZTp1LnR5cGUsZGF0YTpwfX0pfSksaT1hd2FpdCBQcm9taXNlLmFsbChvKTthfHxpLnNvcnQoKHUscCk9PnUubmFtZTxwLm5hbWU/LTE6dS5uYW1lPnAubmFtZT8xOjApO2xldCBsPVtdO2ZvcihsZXQgdT0wO3U8aS5sZW5ndGg7dSsrKWwucHVzaChbaVt1XS5kYXRhLGlbdV0ubmFtZV0pO2xldCBnPShhd2FpdCBtci5ydW5UYXNrcyhsKS5wcm9taXNlKS5tYXAodT0+e2xldCBwPXUuaW1hZ2U7cmV0dXJuIHAuaW1hZ2VUeXBlLmRpbWVuc2lvbj0zLHAuc2l6ZS5wdXNoKDEpLHAuc3BhY2luZy5wdXNoKHQpLHAub3JpZ2luLnB1c2gocikscC5kaXJlY3Rpb249bmV3IEZsb2F0NjRBcnJheSg5KSxwLmRpcmVjdGlvbi5maWxsKDApLHAuZGlyZWN0aW9uWzBdPTEscC5kaXJlY3Rpb25bNF09MSxwLmRpcmVjdGlvbls4XT0xLHB9KSxuPUdlKGcpO3JldHVybiB0eXBlb2YgQT09Im9iamVjdCImJih0eXBlb2YgQS5jb21wb25lbnRUeXBlPCJ1Inx8dHlwZW9mIEEucGl4ZWxUeXBlPCJ1IikmJihuPVQobixBKSkse2ltYWdlOm4sd2ViV29ya2VyUG9vbDptcn19dmFyIFZhPXphO2FzeW5jIGZ1bmN0aW9uIFphKGUsQSx0LHI9e30pe2xldCBhPUE7KHR5cGVvZiByLmNvbXBvbmVudFR5cGU8InUifHx0eXBlb2Ygci5waXhlbFR5cGU8InUiKSYmKGE9VChBLHIpKTtsZXQgbz1yLm1pbWVUeXBlLGk9bWUodCkudG9Mb3dlckNhc2UoKSxsPWUsZj1udWxsO2lmKHR5cGVvZiBvPCJ1IiYmZWUuaGFzKG8pKWY9ZWUuZ2V0KG8pO2Vsc2UgaWYoQWUuaGFzKGkpKWY9QWUuZ2V0KGkpO2Vsc2UgZm9yKGxldCBkIG9mIHRlLnZhbHVlcygpKWlmKGRbMV0hPT1udWxsKXtsZXR7d2ViV29ya2VyOkUsY291bGRXcml0ZTpSLHNlcmlhbGl6ZWRJbWFnZTp3fT1hd2FpdCBkWzFdKGwseGUoYSksdCxyKTtpZihsPUUsUilyZXR1cm57d2ViV29ya2VyOmwsc2VyaWFsaXplZEltYWdlOnd9fWlmKCFmKXRocm93IEVycm9yKCJDb3VsZCBub3QgZmluZCBJTyBmb3I6ICIrdCk7bGV0IG49dGUuZ2V0KGYpWzFdLHt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOnAsc2VyaWFsaXplZEltYWdlOnN9PWF3YWl0IG4obCxhLHQscik7aWYobD11LCFwKXRocm93IEVycm9yKCJDb3VsZCBub3Qgd3JpdGU6ICIrdCk7cmV0dXJue3dlYldvcmtlcjpsLHNlcmlhbGl6ZWRJbWFnZTpzfX12YXIgWGE9WmE7YXN5bmMgZnVuY3Rpb24gJGEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJmZGYtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIGVvPSRhO3ZhciB1cj0nZGF0YTp0ZXh0L2phdmFzY3JpcHQ7Y2hhcnNldD11dGYtOCx2YXIgY2U9U3ltYm9sKCJDb21saW5rLnByb3h5IiksQ3Q9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IiksQnQ9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLE1BPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksZmU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsUXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmQVtjZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gRUEoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLGx0KEEpfX0sRXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LGxlPW5ldyBNYXAoW1sicHJveHkiLFF0XSxbInRocm93IixFdF1dKTtmdW5jdGlvbiBjdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gRUEoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBJKHIpe2lmKCFyfHwhci5kYXRhKXJldHVybjtpZighY3QodCxyLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gXCcke3Iub3JpZ2lufVwnIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6ZyxwYXRoOm59PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksRT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChxKSxvO3RyeXtsZXQgQj1uLnNsaWNlKDAsLTEpLnJlZHVjZSgoYSxDKT0+YVtDXSxBKSxjPW4ucmVkdWNlKChhLEMpPT5hW0NdLEEpO3N3aXRjaChnKXtjYXNlIkdFVCI6bz1jO2JyZWFrO2Nhc2UiU0VUIjpCW24uc2xpY2UoLTEpWzBdXT1xKHIuZGF0YS52YWx1ZSksbz0hMDticmVhaztjYXNlIkFQUExZIjpvPWMuYXBwbHkoQixFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBhPW5ldyBjKC4uLkUpO289bXQoYSl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTphLHBvcnQyOkN9PW5ldyBNZXNzYWdlQ2hhbm5lbDtFQShBLEMpLG89SEEoYSxbYV0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6bz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKEIpe289e3ZhbHVlOkIsW3NBXTowfX1Qcm9taXNlLnJlc29sdmUobykuY2F0Y2goQj0+KHt2YWx1ZTpCLFtzQV06MH0pKS50aGVuKEI9PntsZXRbYyxhXT1RQShCKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLGEpLGc9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLHVlKGUpLE1BIGluIEEmJnR5cGVvZiBBW01BXT09ImZ1bmN0aW9uIiYmQVtNQV0oKSl9KS5jYXRjaChCPT57bGV0W2MsYV09UUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtzQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LGMpLHtpZDppfSksYSl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBmdChBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiB1ZShBKXtmdChBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGx0KEEsZSl7cmV0dXJuIGJBKEEsW10sZSl9ZnVuY3Rpb24gYUEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIGhlKEEpe3JldHVybiB4KEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e3VlKEEpfSl9dmFyIENBPW5ldyBXZWFrTWFwLEJBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPShDQS5nZXQoQSl8fDApLTE7Q0Euc2V0KEEsZSksZT09PTAmJmhlKEEpfSk7ZnVuY3Rpb24gdXQoQSxlKXtsZXQgdD0oQ0EuZ2V0KGUpfHwwKSsxO0NBLnNldChlLHQpLEJBJiZCQS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gaHQoQSl7QkEmJkJBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gYkEoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgST0hMSxyPW5ldyBQcm94eSh0LHtnZXQoaSxnKXtpZihhQShJKSxnPT09QnQpcmV0dXJuKCk9PntodChyKSxoZShBKSxJPSEwfTtpZihnPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9PnJ9O2xldCBuPXgoQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKEU9PkUudG9TdHJpbmcoKSl9KS50aGVuKHEpO3JldHVybiBuLnRoZW4uYmluZChuKX1yZXR1cm4gYkEoQSxbLi4uZSxnXSl9LHNldChpLGcsbil7YUEoSSk7bGV0W0Usb109UUEobik7cmV0dXJuIHgoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGddLm1hcChCPT5CLnRvU3RyaW5nKCkpLHZhbHVlOkV9LG8pLnRoZW4ocSl9LGFwcGx5KGksZyxuKXthQShJKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1DdClyZXR1cm4geChBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKHEpO2lmKEU9PT0iYmluZCIpcmV0dXJuIGJBKEEsZS5zbGljZSgwLC0xKSk7bGV0W28sQl09RWUobik7cmV0dXJuIHgoQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoYz0+Yy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6b30sQikudGhlbihxKX0sY29uc3RydWN0KGksZyl7YUEoSSk7bGV0W24sRV09RWUoZyk7cmV0dXJuIHgoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKG89Pm8udG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Om59LEUpLnRoZW4ocSl9fSk7cmV0dXJuIHV0KHIsQSkscn1mdW5jdGlvbiBkdChBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBFZShBKXtsZXQgZT1BLm1hcChRQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGR0KGUubWFwKHQ9PnRbMV0pKV19dmFyIGRlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIEhBKEEsZSl7cmV0dXJuIGRlLnNldChBLGUpLEF9ZnVuY3Rpb24gbXQoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W2NlXTohMH0pfWZ1bmN0aW9uIFFBKEEpe2ZvcihsZXRbZSx0XW9mIGxlKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZGUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gcShBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBsZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIHgoQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShJPT57bGV0IHI9RHQoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkoZyl7IWcuZGF0YXx8IWcuZGF0YS5pZHx8Zy5kYXRhLmlkIT09cnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSksSShnLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOnJ9LGUpLHQpfSl9ZnVuY3Rpb24gRHQoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIFgoQSxlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShlLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzp5dH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6VEF9PU9iamVjdCxmQT0oQT0+ZT0+e2xldCB0PXl0LmNhbGwoZSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxVPUE9PihBPUEudG9Mb3dlckNhc2UoKSxlPT5mQShlKT09PUEpLGxBPUE9PmU9PnR5cGVvZiBlPT09QSx7aXNBcnJheTpQfT1BcnJheSx2PWxBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiB3dChBKXtyZXR1cm4gQSE9PW51bGwmJiF2KEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIXYoQS5jb25zdHJ1Y3RvcikmJlIoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIHdlPVUoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gcHQoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZ3ZShBLmJ1ZmZlciksZX12YXIgRnQ9bEEoInN0cmluZyIpLFI9bEEoImZ1bmN0aW9uIikscGU9bEEoIm51bWJlciIpLHVBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsU3Q9QT0+QT09PSEwfHxBPT09ITEsY0E9QT0+e2lmKGZBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9VEEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sTnQ9VSgiRGF0ZSIpLFJ0PVUoIkZpbGUiKSxHdD1VKCJCbG9iIiksVXQ9VSgiRmlsZUxpc3QiKSxrdD1BPT51QShBKSYmUihBLnBpcGUpLEx0PUE9PntsZXQgZTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxSKEEuYXBwZW5kKSYmKChlPWZBKEEpKT09PSJmb3JtZGF0YSJ8fGU9PT0ib2JqZWN0IiYmUihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxPdD1VKCJVUkxTZWFyY2hQYXJhbXMiKSxKdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gJChBLGUse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBJLHI7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLFAoQSkpZm9yKEk9MCxyPUEubGVuZ3RoO0k8cjtJKyspZS5jYWxsKG51bGwsQVtJXSxJLEEpO2Vsc2V7bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxnPWkubGVuZ3RoLG47Zm9yKEk9MDtJPGc7SSsrKW49aVtJXSxlLmNhbGwobnVsbCxBW25dLG4sQSl9fWZ1bmN0aW9uIEZlKEEsZSl7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgU2U9KCgpPT50eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsKSgpLE5lPUE9PiF2KEEpJiZBIT09U2U7ZnVuY3Rpb24gcUEoKXtsZXR7Y2FzZWxlc3M6QX09TmUodGhpcykmJnRoaXN8fHt9LGU9e30sdD0oSSxyKT0+e2xldCBpPUEmJkZlKGUscil8fHI7Y0EoZVtpXSkmJmNBKEkpP2VbaV09cUEoZVtpXSxJKTpjQShJKT9lW2ldPXFBKHt9LEkpOlAoSSk/ZVtpXT1JLnNsaWNlKCk6ZVtpXT1JfTtmb3IobGV0IEk9MCxyPWFyZ3VtZW50cy5sZW5ndGg7STxyO0krKylhcmd1bWVudHNbSV0mJiQoYXJndW1lbnRzW0ldLHQpO3JldHVybiBlfXZhciBNdD0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4oJChlLChyLGkpPT57dCYmUihyKT9BW2ldPVgocix0KTpBW2ldPXJ9LHthbGxPd25LZXlzOkl9KSxBKSxidD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLEh0PShBLGUsdCxJKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZS5wcm90b3R5cGUsSSksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTplLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LFl0PShBLGUsdCxJKT0+e2xldCByLGksZyxuPXt9O2lmKGU9ZXx8e30sQT09bnVsbClyZXR1cm4gZTtkb3tmb3Iocj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxpPXIubGVuZ3RoO2ktLSA+MDspZz1yW2ldLCghSXx8SShnLEEsZSkpJiYhbltnXSYmKGVbZ109QVtnXSxuW2ddPSEwKTtBPXQhPT0hMSYmVEEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsZSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIGV9LHF0PShBLGUsdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1lLmxlbmd0aDtsZXQgST1BLmluZGV4T2YoZSx0KTtyZXR1cm4gSSE9PS0xJiZJPT09dH0sVHQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKFAoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIXBlKGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxLdD0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmVEEoVWludDhBcnJheSkpLHh0PShBLGUpPT57bGV0IEk9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxyO2Zvcig7KHI9SS5uZXh0KCkpJiYhci5kb25lOyl7bGV0IGk9ci52YWx1ZTtlLmNhbGwoQSxpWzBdLGlbMV0pfX0sUHQ9KEEsZSk9PntsZXQgdCxJPVtdO2Zvcig7KHQ9QS5leGVjKGUpKSE9PW51bGw7KUkucHVzaCh0KTtyZXR1cm4gSX0sV3Q9VSgiSFRNTEZvcm1FbGVtZW50IiksanQ9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24odCxJLHIpe3JldHVybiBJLnRvVXBwZXJDYXNlKCkrcn0pLERlPSgoe2hhc093blByb3BlcnR5OkF9KT0+KGUsdCk9PkEuY2FsbChlLHQpKShPYmplY3QucHJvdG90eXBlKSxadD1VKCJSZWdFeHAiKSxSZT0oQSxlKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLEk9e307JCh0LChyLGkpPT57ZShyLGksQSkhPT0hMSYmKElbaV09cil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLEkpfSxfdD1BPT57UmUoQSwoZSx0KT0+e2lmKFIoQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCBJPUFbdF07aWYoUihJKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kIFwnIit0KyJcJyIpfSl9fSl9LFZ0PShBLGUpPT57bGV0IHQ9e30sST1yPT57ci5mb3JFYWNoKGk9Pnt0W2ldPSEwfSl9O3JldHVybiBQKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LHp0PSgpPT57fSxYdD0oQSxlKT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6ZSksWUE9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iix5ZT0iMDEyMzQ1Njc4OSIsR2U9e0RJR0lUOnllLEFMUEhBOllBLEFMUEhBX0RJR0lUOllBK1lBLnRvVXBwZXJDYXNlKCkreWV9LHZ0PShBPTE2LGU9R2UuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpJfT1lO2Zvcig7QS0tOyl0Kz1lW01hdGgucmFuZG9tKCkqSXwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gJHQoQSl7cmV0dXJuISEoQSYmUihBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIEFJPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZih1QShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1QKEkpP1tdOnt9O3JldHVybiAkKEksKGcsbik9PntsZXQgRT10KGcscisxKTshdihFKSYmKGlbbl09RSl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sZUk9VSgiQXN5bmNGdW5jdGlvbiIpLHRJPUE9PkEmJih1QShBKXx8UihBKSkmJlIoQS50aGVuKSYmUihBLmNhdGNoKSxzPXtpc0FycmF5OlAsaXNBcnJheUJ1ZmZlcjp3ZSxpc0J1ZmZlcjp3dCxpc0Zvcm1EYXRhOkx0LGlzQXJyYXlCdWZmZXJWaWV3OnB0LGlzU3RyaW5nOkZ0LGlzTnVtYmVyOnBlLGlzQm9vbGVhbjpTdCxpc09iamVjdDp1QSxpc1BsYWluT2JqZWN0OmNBLGlzVW5kZWZpbmVkOnYsaXNEYXRlOk50LGlzRmlsZTpSdCxpc0Jsb2I6R3QsaXNSZWdFeHA6WnQsaXNGdW5jdGlvbjpSLGlzU3RyZWFtOmt0LGlzVVJMU2VhcmNoUGFyYW1zOk90LGlzVHlwZWRBcnJheTpLdCxpc0ZpbGVMaXN0OlV0LGZvckVhY2g6JCxtZXJnZTpxQSxleHRlbmQ6TXQsdHJpbTpKdCxzdHJpcEJPTTpidCxpbmhlcml0czpIdCx0b0ZsYXRPYmplY3Q6WXQsa2luZE9mOmZBLGtpbmRPZlRlc3Q6VSxlbmRzV2l0aDpxdCx0b0FycmF5OlR0LGZvckVhY2hFbnRyeTp4dCxtYXRjaEFsbDpQdCxpc0hUTUxGb3JtOld0LGhhc093blByb3BlcnR5OkRlLGhhc093blByb3A6RGUscmVkdWNlRGVzY3JpcHRvcnM6UmUsZnJlZXplTWV0aG9kczpfdCx0b09iamVjdFNldDpWdCx0b0NhbWVsQ2FzZTpqdCxub29wOnp0LHRvRmluaXRlTnVtYmVyOlh0LGZpbmRLZXk6RmUsZ2xvYmFsOlNlLGlzQ29udGV4dERlZmluZWQ6TmUsQUxQSEFCRVQ6R2UsZ2VuZXJhdGVTdHJpbmc6dnQsaXNTcGVjQ29tcGxpYW50Rm9ybTokdCx0b0pTT05PYmplY3Q6QUksaXNBc3luY0ZuOmVJLGlzVGhlbmFibGU6dEl9O2Z1bmN0aW9uIFcoQSxlLHQsSSxyKXtFcnJvci5jYWxsKHRoaXMpLEVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsdGhpcy5jb25zdHJ1Y3Rvcik6dGhpcy5zdGFjaz1uZXcgRXJyb3IoKS5zdGFjayx0aGlzLm1lc3NhZ2U9QSx0aGlzLm5hbWU9IkF4aW9zRXJyb3IiLGUmJih0aGlzLmNvZGU9ZSksdCYmKHRoaXMuY29uZmlnPXQpLEkmJih0aGlzLnJlcXVlc3Q9SSksciYmKHRoaXMucmVzcG9uc2U9cil9cy5pbmhlcml0cyhXLEVycm9yLHt0b0pTT046ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6cy50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX19KTt2YXIgVWU9Vy5wcm90b3R5cGUsa2U9e307WyJFUlJfQkFEX09QVElPTl9WQUxVRSIsIkVSUl9CQURfT1BUSU9OIiwiRUNPTk5BQk9SVEVEIiwiRVRJTUVET1VUIiwiRVJSX05FVFdPUksiLCJFUlJfRlJfVE9PX01BTllfUkVESVJFQ1RTIiwiRVJSX0RFUFJFQ0FURUQiLCJFUlJfQkFEX1JFU1BPTlNFIiwiRVJSX0JBRF9SRVFVRVNUIiwiRVJSX0NBTkNFTEVEIiwiRVJSX05PVF9TVVBQT1JUIiwiRVJSX0lOVkFMSURfVVJMIl0uZm9yRWFjaChBPT57a2VbQV09e3ZhbHVlOkF9fSk7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVyxrZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KFVlLCJpc0F4aW9zRXJyb3IiLHt2YWx1ZTohMH0pO1cuZnJvbT0oQSxlLHQsSSxyLGkpPT57bGV0IGc9T2JqZWN0LmNyZWF0ZShVZSk7cmV0dXJuIHMudG9GbGF0T2JqZWN0KEEsZyxmdW5jdGlvbihFKXtyZXR1cm4gRSE9PUVycm9yLnByb3RvdHlwZX0sbj0+biE9PSJpc0F4aW9zRXJyb3IiKSxXLmNhbGwoZyxBLm1lc3NhZ2UsZSx0LEksciksZy5jYXVzZT1BLGcubmFtZT1BLm5hbWUsaSYmT2JqZWN0LmFzc2lnbihnLGkpLGd9O3ZhciBsPVc7dmFyIGhBPW51bGw7ZnVuY3Rpb24gS0EoQSl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChBKXx8cy5pc0FycmF5KEEpfWZ1bmN0aW9uIE9lKEEpe3JldHVybiBzLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIExlKEEsZSx0KXtyZXR1cm4gQT9BLmNvbmNhdChlKS5tYXAoZnVuY3Rpb24ocixpKXtyZXR1cm4gcj1PZShyKSwhdCYmaT8iWyIrcisiXSI6cn0pLmpvaW4odD8iLiI6IiIpOmV9ZnVuY3Rpb24gSUkoQSl7cmV0dXJuIHMuaXNBcnJheShBKSYmIUEuc29tZShLQSl9dmFyIHJJPXMudG9GbGF0T2JqZWN0KHMse30sbnVsbCxmdW5jdGlvbihlKXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QoZSl9KTtmdW5jdGlvbiBpSShBLGUsdCl7aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7ZT1lfHxuZXcoaEF8fEZvcm1EYXRhKSx0PXMudG9GbGF0T2JqZWN0KHQse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLG0pe3JldHVybiFzLmlzVW5kZWZpbmVkKG1bZl0pfSk7bGV0IEk9dC5tZXRhVG9rZW5zLHI9dC52aXNpdG9yfHxCLGk9dC5kb3RzLGc9dC5pbmRleGVzLEU9KHQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmcy5pc1NwZWNDb21wbGlhbnRGb3JtKGUpO2lmKCFzLmlzRnVuY3Rpb24ocikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBvKFEpe2lmKFE9PT1udWxsKXJldHVybiIiO2lmKHMuaXNEYXRlKFEpKXJldHVybiBRLnRvSVNPU3RyaW5nKCk7aWYoIUUmJnMuaXNCbG9iKFEpKXRocm93IG5ldyBsKCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBzLmlzQXJyYXlCdWZmZXIoUSl8fHMuaXNUeXBlZEFycmF5KFEpP0UmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtRXSk6QnVmZmVyLmZyb20oUSk6UX1mdW5jdGlvbiBCKFEsZixtKXtsZXQgdz1RO2lmKFEmJiFtJiZ0eXBlb2YgUT09Im9iamVjdCIpe2lmKHMuZW5kc1dpdGgoZiwie30iKSlmPUk/ZjpmLnNsaWNlKDAsLTIpLFE9SlNPTi5zdHJpbmdpZnkoUSk7ZWxzZSBpZihzLmlzQXJyYXkoUSkmJklJKFEpfHwocy5pc0ZpbGVMaXN0KFEpfHxzLmVuZHNXaXRoKGYsIltdIikpJiYodz1zLnRvQXJyYXkoUSkpKXJldHVybiBmPU9lKGYpLHcuZm9yRWFjaChmdW5jdGlvbihLLEpBKXshKHMuaXNVbmRlZmluZWQoSyl8fEs9PT1udWxsKSYmZS5hcHBlbmQoZz09PSEwP0xlKFtmXSxKQSxpKTpnPT09bnVsbD9mOmYrIltdIixvKEspKX0pLCExfXJldHVybiBLQShRKT8hMDooZS5hcHBlbmQoTGUobSxmLGkpLG8oUSkpLCExKX1sZXQgYz1bXSxhPU9iamVjdC5hc3NpZ24ockkse2RlZmF1bHRWaXNpdG9yOkIsY29udmVydFZhbHVlOm8saXNWaXNpdGFibGU6S0F9KTtmdW5jdGlvbiBDKFEsZil7aWYoIXMuaXNVbmRlZmluZWQoUSkpe2lmKGMuaW5kZXhPZihRKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Yy5wdXNoKFEpLHMuZm9yRWFjaChRLGZ1bmN0aW9uKHcsTyl7KCEocy5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZyLmNhbGwoZSx3LHMuaXNTdHJpbmcoTyk/Ty50cmltKCk6TyxmLGEpKT09PSEwJiZDKHcsZj9mLmNvbmNhdChPKTpbT10pfSksYy5wb3AoKX19aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBDKEEpLGV9dmFyIEo9aUk7ZnVuY3Rpb24gSmUoQSl7bGV0IGU9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIiwiJTI1MDAiOiJcXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shXCcoKX5dfCUyNTIwfCUyNTAwL2csZnVuY3Rpb24oSSl7cmV0dXJuIGVbSV19KX1mdW5jdGlvbiBNZShBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJkooQSx0aGlzLGUpfXZhciBiZT1NZS5wcm90b3R5cGU7YmUuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O2JlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24oSSl7cmV0dXJuIGUuY2FsbCh0aGlzLEksSmUpfTpKZTtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiB0KHJbMF0pKyI9Iit0KHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgZEE9TWU7ZnVuY3Rpb24gZ0koQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lMjUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNTI0L2csIiQiKS5yZXBsYWNlKC8lMjUyQy9naSwiLCIpLnJlcGxhY2UoLyUyNTIwL2csIisiKS5yZXBsYWNlKC8lMjU1Qi9naSwiWyIpLnJlcGxhY2UoLyUyNTVEL2dpLCJdIil9ZnVuY3Rpb24gQUEoQSxlLHQpe2lmKCFlKXJldHVybiBBO2xldCBJPXQmJnQuZW5jb2RlfHxnSSxyPXQmJnQuc2VyaWFsaXplLGk7aWYocj9pPXIoZSx0KTppPXMuaXNVUkxTZWFyY2hQYXJhbXMoZSk/ZS50b1N0cmluZygpOm5ldyBkQShlLHQpLnRvU3RyaW5nKEkpLGkpe2xldCBnPUEuaW5kZXhPZigiJTIzIik7ZyE9PS0xJiYoQT1BLnNsaWNlKDAsZykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIHhBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LEkpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6ST9JLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ST9JLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihJKXtJIT09bnVsbCYmZShJKX0pfX0sUEE9eEE7dmFyIG1BPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgSGU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOmRBO3ZhciBZZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIHFlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIG9JPSgoKT0+e2xldCBBO3JldHVybiB0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmKChBPW5hdmlnYXRvci5wcm9kdWN0KT09PSJSZWFjdE5hdGl2ZSJ8fEE9PT0iTmF0aXZlU2NyaXB0Inx8QT09PSJOUyIpPyExOnR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUifSkoKSxuST0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKSxEPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkhlLEZvcm1EYXRhOlllLEJsb2I6cWV9LGlzU3RhbmRhcmRCcm93c2VyRW52Om9JLGlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52Om5JLHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTtmdW5jdGlvbiBXQShBLGUpe3JldHVybiBKKEEsbmV3IEQuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LEkscixpKXtyZXR1cm4gRC5pc05vZGUmJnMuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKEksdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LGUpKX1mdW5jdGlvbiBhSShBKXtyZXR1cm4gcy5tYXRjaEFsbCgvXFx3K3xcXFsoXFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIHNJKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSksSSxyPXQubGVuZ3RoLGk7Zm9yKEk9MDtJPHI7SSsrKWk9dFtJXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gQ0koQSl7ZnVuY3Rpb24gZSh0LEkscixpKXtsZXQgZz10W2krK10sbj1OdW1iZXIuaXNGaW5pdGUoK2cpLEU9aT49dC5sZW5ndGg7cmV0dXJuIGc9IWcmJnMuaXNBcnJheShyKT9yLmxlbmd0aDpnLEU/KHMuaGFzT3duUHJvcChyLGcpP3JbZ109W3JbZ10sSV06cltnXT1JLCFuKTooKCFyW2ddfHwhcy5pc09iamVjdChyW2ddKSkmJihyW2ddPVtdKSxlKHQsSSxyW2ddLGkpJiZzLmlzQXJyYXkocltnXSkmJihyW2ddPXNJKHJbZ10pKSwhbil9aWYocy5pc0Zvcm1EYXRhKEEpJiZzLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIHMuZm9yRWFjaEVudHJ5KEEsKEkscik9PntlKGFJKEkpLHIsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIERBPUNJO3ZhciBCST17IkNvbnRlbnQtVHlwZSI6dm9pZCAwfTtmdW5jdGlvbiBRSShBLGUsdCl7aWYocy5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKGV8fEpTT04ucGFyc2UpKEEpLHMudHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgeUE9e3RyYW5zaXRpb25hbDptQSxhZGFwdGVyOlsieGhyIiwiaHR0cCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7bGV0IEk9dC5nZXRDb250ZW50VHlwZSgpfHwiIixyPUkuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLGk9cy5pc09iamVjdChlKTtpZihpJiZzLmlzSFRNTEZvcm0oZSkmJihlPW5ldyBGb3JtRGF0YShlKSkscy5pc0Zvcm1EYXRhKGUpKXJldHVybiByJiZyP0pTT04uc3RyaW5naWZ5KERBKGUpKTplO2lmKHMuaXNBcnJheUJ1ZmZlcihlKXx8cy5pc0J1ZmZlcihlKXx8cy5pc1N0cmVhbShlKXx8cy5pc0ZpbGUoZSl8fHMuaXNCbG9iKGUpKXJldHVybiBlO2lmKHMuaXNBcnJheUJ1ZmZlclZpZXcoZSkpcmV0dXJuIGUuYnVmZmVyO2lmKHMuaXNVUkxTZWFyY2hQYXJhbXMoZSkpcmV0dXJuIHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksZS50b1N0cmluZygpO2xldCBuO2lmKGkpe2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIFdBKGUsdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigobj1zLmlzRmlsZUxpc3QoZSkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEU9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBKKG4/eyJmaWxlc1tdIjplfTplLEUmJm5ldyBFLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gaXx8cj8odC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLFFJKGUpKTplfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKGUpe2xldCB0PXRoaXMudHJhbnNpdGlvbmFsfHx5QS50cmFuc2l0aW9uYWwsST10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLHI9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYoZSYmcy5pc1N0cmluZyhlKSYmKEkmJiF0aGlzLnJlc3BvbnNlVHlwZXx8cikpe2xldCBnPSEodCYmdC5zaWxlbnRKU09OUGFyc2luZykmJnI7dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpfWNhdGNoKG4pe2lmKGcpdGhyb3cgbi5uYW1lPT09IlN5bnRheEVycm9yIj9sLmZyb20obixsLkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOm59fXJldHVybiBlfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpELmNsYXNzZXMuRm9ybURhdGEsQmxvYjpELmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTIwMCYmZTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoifX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiXSxmdW5jdGlvbihlKXt5QS5oZWFkZXJzW2VdPXt9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7eUEuaGVhZGVyc1tlXT1zLm1lcmdlKEJJKX0pO3ZhciBqPXlBO3ZhciBFST1zLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLFRlPUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgJTBBYCkuZm9yRWFjaChmdW5jdGlvbihnKXtyPWcuaW5kZXhPZigiOiIpLHQ9Zy5zdWJzdHJpbmcoMCxyKS50cmltKCkudG9Mb3dlckNhc2UoKSxJPWcuc3Vic3RyaW5nKHIrMSkudHJpbSgpLCEoIXR8fGVbdF0mJkVJW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2goSSk6ZVt0XT1bSV06ZVt0XT1lW3RdP2VbdF0rIiwgIitJOkkpfSksZX07dmFyIEtlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiB3QShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6cy5pc0FycmF5KEEpP0EubWFwKHdBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gY0koQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15cXHMsOz1dKylcXHMqKD86PVxccyooW14sO10rKSk/L2csSTtmb3IoO0k9dC5leGVjKEEpOyllW0lbMV1dPUlbMl07cmV0dXJuIGV9dmFyIGZJPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhJTIzJCUmXCcqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIGpBKEEsZSx0LEkscil7aWYocy5pc0Z1bmN0aW9uKEkpKXJldHVybiBJLmNhbGwodGhpcyxlLHQpO2lmKHImJihlPXQpLCEhcy5pc1N0cmluZyhlKSl7aWYocy5pc1N0cmluZyhJKSlyZXR1cm4gZS5pbmRleE9mKEkpIT09LTE7aWYocy5pc1JlZ0V4cChJKSlyZXR1cm4gSS50ZXN0KGUpfX1mdW5jdGlvbiBsSShBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxcZF0pKFxcdyopL2csKGUsdCxJKT0+dC50b1VwcGVyQ2FzZSgpK0kpfWZ1bmN0aW9uIHVJKEEsZSl7bGV0IHQ9cy50b0NhbWVsQ2FzZSgiICIrZSk7WyJnZXQiLCJzZXQiLCJoYXMiXS5mb3JFYWNoKEk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxJK3Qse3ZhbHVlOmZ1bmN0aW9uKHIsaSxnKXtyZXR1cm4gdGhpc1tJXS5jYWxsKHRoaXMsZSxyLGksZyl9LGNvbmZpZ3VyYWJsZTohMH0pfSl9dmFyIFo9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkobixFLG8pe2xldCBCPWVBKEUpO2lmKCFCKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgYz1zLmZpbmRLZXkocixCKTsoIWN8fHJbY109PT12b2lkIDB8fG89PT0hMHx8bz09PXZvaWQgMCYmcltjXSE9PSExKSYmKHJbY3x8RV09d0EobikpfWxldCBnPShuLEUpPT5zLmZvckVhY2gobiwobyxCKT0+aShvLEIsRSkpO3JldHVybiBzLmlzUGxhaW5PYmplY3QoZSl8fGUgaW5zdGFuY2VvZiB0aGlzLmNvbnN0cnVjdG9yP2coZSx0KTpzLmlzU3RyaW5nKGUpJiYoZT1lLnRyaW0oKSkmJiFmSShlKT9nKFRlKGUpLHQpOmUhPW51bGwmJmkodCxlLEkpLHRoaXN9Z2V0KGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gY0kocik7aWYocy5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKHMuaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGpBKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkoZyl7aWYoZz1lQShnKSxnKXtsZXQgbj1zLmZpbmRLZXkoSSxnKTtuJiYoIXR8fGpBKEksSVtuXSxuLHQpKSYmKGRlbGV0ZSBJW25dLHI9ITApfX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGpBKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IGc9cy5maW5kS2V5KEksaSk7aWYoZyl7dFtnXT13QShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IG49ZT9sSShpKTpTdHJpbmcoaSkudHJpbSgpO24hPT1pJiZkZWxldGUgdFtpXSx0W25dPXdBKHIpLElbbl09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gcy5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJnMuaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYCUwQWApfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0aGlzP2U6bmV3IHRoaXMoZSl9c3RhdGljIGNvbmNhdChlLC4uLnQpe2xldCBJPW5ldyB0aGlzKGUpO3JldHVybiB0LmZvckVhY2gocj0+SS5zZXQocikpLEl9c3RhdGljIGFjY2Vzc29yKGUpe2xldCBJPSh0aGlzW0tlXT10aGlzW0tlXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLHI9dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gaShnKXtsZXQgbj1lQShnKTtJW25dfHwodUkocixnKSxJW25dPSEwKX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHRoaXN9fTtaLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtzLmZyZWV6ZU1ldGhvZHMoWi5wcm90b3R5cGUpO3MuZnJlZXplTWV0aG9kcyhaKTt2YXIgcD1aO2Z1bmN0aW9uIHRBKEEsZSl7bGV0IHQ9dGhpc3x8aixJPWV8fHQscj1wLmZyb20oSS5oZWFkZXJzKSxpPUkuZGF0YTtyZXR1cm4gcy5mb3JFYWNoKEEsZnVuY3Rpb24obil7aT1uLmNhbGwodCxpLHIubm9ybWFsaXplKCksZT9lLnN0YXR1czp2b2lkIDApfSksci5ub3JtYWxpemUoKSxpfWZ1bmN0aW9uIElBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9ZnVuY3Rpb24geGUoQSxlLHQpe2wuY2FsbCh0aGlzLEE/PyJjYW5jZWxlZCIsbC5FUlJfQ0FOQ0VMRUQsZSx0KSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IifXMuaW5oZXJpdHMoeGUsbCx7X19DQU5DRUxfXzohMH0pO3ZhciBNPXhlO2Z1bmN0aW9uIFpBKEEsZSx0KXtsZXQgST10LmNvbmZpZy52YWxpZGF0ZVN0YXR1czshdC5zdGF0dXN8fCFJfHxJKHQuc3RhdHVzKT9BKHQpOmUobmV3IGwoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIit0LnN0YXR1cyxbbC5FUlJfQkFEX1JFUVVFU1QsbC5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKHQuc3RhdHVzLzEwMCktNF0sdC5jb25maWcsdC5yZXF1ZXN0LHQpKX12YXIgUGU9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LEkscixpLGcsbil7bGV0IEU9W107RS5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChJKSkscy5pc051bWJlcihyKSYmRS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUocikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmRS5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhnKSYmRS5wdXNoKCJkb21haW49IitnKSxuPT09ITAmJkUucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPUUuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgST1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xcXFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIEk/ZGVjb2RlVVJJQ29tcG9uZW50KElbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBfQShBKXtyZXR1cm4vXihbYS16XVthLXpcXGQrXFwtLl0qOik/XFwvXFwvL2kudGVzdChBKX1mdW5jdGlvbiBWQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXFwvKyQvLCIiKSsiLyIrZS5yZXBsYWNlKC9eXFwvKy8sIiIpOkF9ZnVuY3Rpb24gckEoQSxlKXtyZXR1cm4gQSYmIV9BKGUpP1ZBKEEsZSk6ZX12YXIgV2U9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBlPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIiksSTtmdW5jdGlvbiByKGkpe2xldCBnPWk7cmV0dXJuIGUmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsZyksZz10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixnKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiUyMy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIEk9cih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oZyl7bGV0IG49cy5pc1N0cmluZyhnKT9yKGcpOmc7cmV0dXJuIG4ucHJvdG9jb2w9PT1JLnByb3RvY29sJiZuLmhvc3Q9PT1JLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIHpBKEEpe2xldCBlPS9eKFstK1xcd117MSwyNX0pKDo/XFwvXFwvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBoSShBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsZztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKEUpe2xldCBvPURhdGUubm93KCksQj1JW2ldO2d8fChnPW8pLHRbcl09RSxJW3JdPW87bGV0IGM9aSxhPTA7Zm9yKDtjIT09cjspYSs9dFtjKytdLGM9YyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksby1nPGUpcmV0dXJuO2xldCBDPUImJm8tQjtyZXR1cm4gQz9NYXRoLnJvdW5kKGEqMWUzL0MpOnZvaWQgMH19dmFyIGplPWhJO2Z1bmN0aW9uIFplKEEsZSl7bGV0IHQ9MCxJPWplKDUwLDI1MCk7cmV0dXJuIHI9PntsZXQgaT1yLmxvYWRlZCxnPXIubGVuZ3RoQ29tcHV0YWJsZT9yLnRvdGFsOnZvaWQgMCxuPWktdCxFPUkobiksbz1pPD1nO3Q9aTtsZXQgQj17bG9hZGVkOmksdG90YWw6Zyxwcm9ncmVzczpnP2kvZzp2b2lkIDAsYnl0ZXM6bixyYXRlOkV8fHZvaWQgMCxlc3RpbWF0ZWQ6RSYmZyYmbz8oZy1pKS9FOnZvaWQgMCxldmVudDpyfTtCW2U/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsQShCKX19dmFyIGRJPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsX2U9ZEkmJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LEkpe2xldCByPUEuZGF0YSxpPXAuZnJvbShBLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGc9QS5yZXNwb25zZVR5cGUsbjtmdW5jdGlvbiBFKCl7QS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShuKSxBLnNpZ25hbCYmQS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG4pfXMuaXNGb3JtRGF0YShyKSYmKEQuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEQuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/aS5zZXRDb250ZW50VHlwZSghMSk6aS5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YTsiLCExKSk7bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IEM9QS5hdXRoLnVzZXJuYW1lfHwiIixRPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoQysiOiIrUSkpfWxldCBCPXJBKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksQUEoQixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIGMoKXtpZighbylyZXR1cm47bGV0IEM9cC5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksZj17ZGF0YTohZ3x8Zz09PSJ0ZXh0Inx8Zz09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOkMsY29uZmlnOkEscmVxdWVzdDpvfTtaQShmdW5jdGlvbih3KXt0KHcpLEUoKX0sZnVuY3Rpb24odyl7SSh3KSxFKCl9LGYpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9YzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoYyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihJKG5ldyBsKCJSZXF1ZXN0IGFib3J0ZWQiLGwuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe0kobmV3IGwoIk5ldHdvcmsgRXJyb3IiLGwuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBRPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixmPUEudHJhbnNpdGlvbmFsfHxtQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihRPUEudGltZW91dEVycm9yTWVzc2FnZSksSShuZXcgbChRLGYuY2xhcmlmeVRpbWVvdXRFcnJvcj9sLkVUSU1FRE9VVDpsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LEQuaXNTdGFuZGFyZEJyb3dzZXJFbnYpe2xldCBDPShBLndpdGhDcmVkZW50aWFsc3x8V2UoQikpJiZBLnhzcmZDb29raWVOYW1lJiZQZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO0MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsQyl9cj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBvJiZzLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihRLGYpe28uc2V0UmVxdWVzdEhlYWRlcihmLFEpfSkscy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChvLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxnJiZnIT09Impzb24iJiYoby5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLnVwbG9hZCYmby51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihuPUM9PntvJiYoSSghQ3x8Qy50eXBlP25ldyBNKG51bGwsQSxvKTpDKSxvLmFib3J0KCksbz1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobiksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP24oKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbikpKTtsZXQgYT16QShCKTtpZihhJiZELnByb3RvY29scy5pbmRleE9mKGEpPT09LTEpe0kobmV3IGwoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrYSsiOiIsbC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1vLnNlbmQocnx8bnVsbCl9KX07dmFyIHBBPXtodHRwOmhBLHhocjpfZX07cy5mb3JFYWNoKHBBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyIFZlPXtnZXRBZGFwdGVyOkE9PntBPXMuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsdCxJO2ZvcihsZXQgcj0wO3I8ZSYmKHQ9QVtyXSwhKEk9cy5pc1N0cmluZyh0KT9wQVt0LnRvTG93ZXJDYXNlKCldOnQpKTtyKyspO2lmKCFJKXRocm93IEk9PT0hMT9uZXcgbChgQWRhcHRlciAke3R9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50YCwiRVJSX05PVF9TVVBQT1JUIik6bmV3IEVycm9yKHMuaGFzT3duUHJvcChwQSx0KT9gQWRhcHRlciBcJyR7dH1cJyBpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZGA6YFVua25vd24gYWRhcHRlciBcJyR7dH1cJ2ApO2lmKCFzLmlzRnVuY3Rpb24oSSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiYWRhcHRlciBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBJfSxhZGFwdGVyczpwQX07ZnVuY3Rpb24gWEEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IE0obnVsbCxBKX1mdW5jdGlvbiBGQShBKXtyZXR1cm4gWEEoQSksQS5oZWFkZXJzPXAuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksVmUuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fGouYWRhcHRlcikoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gWEEoQSksSS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1wLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gSUEoSSl8fChYQShBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1wLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIHplPUE9PkEgaW5zdGFuY2VvZiBwP0EudG9KU09OKCk6QTtmdW5jdGlvbiBrKEEsZSl7ZT1lfHx7fTtsZXQgdD17fTtmdW5jdGlvbiBJKG8sQixjKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KG8pJiZzLmlzUGxhaW5PYmplY3QoQik/cy5tZXJnZS5jYWxsKHtjYXNlbGVzczpjfSxvLEIpOnMuaXNQbGFpbk9iamVjdChCKT9zLm1lcmdlKHt9LEIpOnMuaXNBcnJheShCKT9CLnNsaWNlKCk6Qn1mdW5jdGlvbiByKG8sQixjKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyxjKX1lbHNlIHJldHVybiBJKG8sQixjKX1mdW5jdGlvbiBpKG8sQil7aWYoIXMuaXNVbmRlZmluZWQoQikpcmV0dXJuIEkodm9pZCAwLEIpfWZ1bmN0aW9uIGcobyxCKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyl9ZWxzZSByZXR1cm4gSSh2b2lkIDAsQil9ZnVuY3Rpb24gbihvLEIsYyl7aWYoYyBpbiBlKXJldHVybiBJKG8sQik7aWYoYyBpbiBBKXJldHVybiBJKHZvaWQgMCxvKX1sZXQgRT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsYWRhcHRlcjpnLHJlc3BvbnNlVHlwZTpnLHhzcmZDb29raWVOYW1lOmcseHNyZkhlYWRlck5hbWU6ZyxvblVwbG9hZFByb2dyZXNzOmcsb25Eb3dubG9hZFByb2dyZXNzOmcsZGVjb21wcmVzczpnLG1heENvbnRlbnRMZW5ndGg6ZyxtYXhCb2R5TGVuZ3RoOmcsYmVmb3JlUmVkaXJlY3Q6Zyx0cmFuc3BvcnQ6ZyxodHRwQWdlbnQ6ZyxodHRwc0FnZW50OmcsY2FuY2VsVG9rZW46Zyxzb2NrZXRQYXRoOmcscmVzcG9uc2VFbmNvZGluZzpnLHZhbGlkYXRlU3RhdHVzOm4saGVhZGVyczoobyxCKT0+cih6ZShvKSx6ZShCKSwhMCl9O3JldHVybiBzLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihCKXtsZXQgYz1FW0JdfHxyLGE9YyhBW0JdLGVbQl0sQik7cy5pc1VuZGVmaW5lZChhKSYmYyE9PW58fCh0W0JdPWEpfSksdH12YXIgU0E9IjEuNC4wIjt2YXIgdkE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57dkFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIFhlPXt9O3ZBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQsSSl7ZnVuY3Rpb24gcihpLGcpe3JldHVybiJbQXhpb3MgdiIrU0ErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIraSsiXCciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4oaSxnLG4pPT57aWYoZT09PSExKXRocm93IG5ldyBsKHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksbC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFYZVtnXSYmKFhlW2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKGksZyxuKTohMH19O2Z1bmN0aW9uIG1JKEEsZSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGwoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgaT1JW3JdLGc9ZVtpXTtpZihnKXtsZXQgbj1BW2ldLEU9bj09PXZvaWQgMHx8ZyhuLGksQSk7aWYoRSE9PSEwKXRocm93IG5ldyBsKCJvcHRpb24gIitpKyIgbXVzdCBiZSAiK0UsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyBsKCJVbmtub3duIG9wdGlvbiAiK2ksbC5FUlJfQkFEX09QVElPTil9fXZhciBOQT17YXNzZXJ0T3B0aW9uczptSSx2YWxpZGF0b3JzOnZBfTt2YXIgYj1OQS52YWxpZGF0b3JzLF89Y2xhc3N7Y29uc3RydWN0b3IoZSl7dGhpcy5kZWZhdWx0cz1lLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBQQSxyZXNwb25zZTpuZXcgUEF9fXJlcXVlc3QoZSx0KXt0eXBlb2YgZT09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9ZSk6dD1lfHx7fSx0PWsodGhpcy5kZWZhdWx0cyx0KTtsZXR7dHJhbnNpdGlvbmFsOkkscGFyYW1zU2VyaWFsaXplcjpyLGhlYWRlcnM6aX09dDtJIT09dm9pZCAwJiZOQS5hc3NlcnRPcHRpb25zKEkse3NpbGVudEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Yi50cmFuc2l0aW9uYWwoYi5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbil9LCExKSxyIT1udWxsJiYocy5pc0Z1bmN0aW9uKHIpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9Ok5BLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOmIuZnVuY3Rpb24sc2VyaWFsaXplOmIuZnVuY3Rpb259LCEwKSksdC5tZXRob2Q9KHQubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGc7Zz1pJiZzLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKSxnJiZzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBpW1FdfSksdC5oZWFkZXJzPXAuY29uY2F0KGcsaSk7bGV0IG49W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7dHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITF8fChFPUUmJmYuc3luY2hyb25vdXMsbi51bnNoaWZ0KGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpKX0pO2xldCBvPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZil7by5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IEIsYz0wLGE7aWYoIUUpe2xldCBRPVtGQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKFEudW5zaGlmdC5hcHBseShRLG4pLFEucHVzaC5hcHBseShRLG8pLGE9US5sZW5ndGgsQj1Qcm9taXNlLnJlc29sdmUodCk7YzxhOylCPUIudGhlbihRW2MrK10sUVtjKytdKTtyZXR1cm4gQn1hPW4ubGVuZ3RoO2xldCBDPXQ7Zm9yKGM9MDtjPGE7KXtsZXQgUT1uW2MrK10sZj1uW2MrK107dHJ5e0M9UShDKX1jYXRjaChtKXtmLmNhbGwodGhpcyxtKTticmVha319dHJ5e0I9RkEuY2FsbCh0aGlzLEMpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3IoYz0wLGE9by5sZW5ndGg7YzxhOylCPUIudGhlbihvW2MrK10sb1tjKytdKTtyZXR1cm4gQn1nZXRVcmkoZSl7ZT1rKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9ckEoZS5iYXNlVVJMLGUudXJsKTtyZXR1cm4gQUEodCxlLnBhcmFtcyxlLnBhcmFtc1NlcmlhbGl6ZXIpfX07cy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihlKXtfLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LEkpe3JldHVybiB0aGlzLnJlcXVlc3QoayhJfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChJKXtyZXR1cm4gZnVuY3Rpb24oaSxnLG4pe3JldHVybiB0aGlzLnJlcXVlc3QoayhufHx7fSx7bWV0aG9kOmUsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDppLGRhdGE6Z30pKX19Xy5wcm90b3R5cGVbZV09dCgpLF8ucHJvdG90eXBlW2UrIkZvcm0iXT10KCEwKX0pO3ZhciBpQT1fO3ZhciAkQT1jbGFzcyBBe2NvbnN0cnVjdG9yKGUpe2lmKHR5cGVvZiBlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dD1pfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IGk9SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2ktLSA+MDspSS5fbGlzdGVuZXJzW2ldKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBpLGc9bmV3IFByb21pc2Uobj0+e0kuc3Vic2NyaWJlKG4pLGk9bn0pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShpKX0sZ30sZShmdW5jdGlvbihpLGcsbil7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgTShpLGcsbiksdChJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfXVuc3Vic2NyaWJlKGUpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKGUpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgZTtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24ocil7ZT1yfSksY2FuY2VsOmV9fX0sdmU9JEE7ZnVuY3Rpb24gQWUoQSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBBLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGVlKEEpe3JldHVybiBzLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciB0ZT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXModGUpLmZvckVhY2goKFtBLGVdKT0+e3RlW2VdPUF9KTt2YXIgJGU9dGU7ZnVuY3Rpb24gQXQoQSl7bGV0IGU9bmV3IGlBKEEpLHQ9WChpQS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gcy5leHRlbmQodCxpQS5wcm90b3R5cGUsZSx7YWxsT3duS2V5czohMH0pLHMuZXh0ZW5kKHQsZSxudWxsLHthbGxPd25LZXlzOiEwfSksdC5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIEF0KGsoQSxyKSl9LHR9dmFyIGg9QXQoaik7aC5BeGlvcz1pQTtoLkNhbmNlbGVkRXJyb3I9TTtoLkNhbmNlbFRva2VuPXZlO2guaXNDYW5jZWw9SUE7aC5WRVJTSU9OPVNBO2gudG9Gb3JtRGF0YT1KO2guQXhpb3NFcnJvcj1sO2guQ2FuY2VsPWguQ2FuY2VsZWRFcnJvcjtoLmFsbD1mdW5jdGlvbihlKXtyZXR1cm4gUHJvbWlzZS5hbGwoZSl9O2guc3ByZWFkPUFlO2guaXNBeGlvc0Vycm9yPWVlO2gubWVyZ2VDb25maWc9aztoLkF4aW9zSGVhZGVycz1wO2guZm9ybVRvSlNPTj1BPT5EQShzLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO2guSHR0cFN0YXR1c0NvZGU9JGU7aC5kZWZhdWx0PWg7dmFyIFJBPWg7dmFye0F4aW9zOlNnLEF4aW9zRXJyb3I6TmcsQ2FuY2VsZWRFcnJvcjpSZyxpc0NhbmNlbDpHZyxDYW5jZWxUb2tlbjpVZyxWRVJTSU9OOmtnLGFsbDpMZyxDYW5jZWw6T2csaXNBeGlvc0Vycm9yOkpnLHNwcmVhZDpNZyx0b0Zvcm1EYXRhOmJnLEF4aW9zSGVhZGVyczpIZyxIdHRwU3RhdHVzQ29kZTpZZyxmb3JtVG9KU09OOnFnLG1lcmdlQ29uZmlnOlRnfT1SQTt2YXIgZ0EsTCxyZSxJZT17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe3JlPW5ldyBVaW50OEFycmF5KEwuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSxHQT1jbGFzc3tpbml0KCl7cmV0dXJuIGdBfHwodHlwZW9mIGZldGNoPCJ1Ij9nQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK2V0KS50aGVuKGU9PmUuYXJyYXlCdWZmZXIoKSkudGhlbihlPT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShlLEllKSkudGhlbih0aGlzLl9pbml0KTpnQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbShldCwiYmFzZTY0IiksSWUpLnRoZW4odGhpcy5faW5pdCksZ0EpfV9pbml0KGUpe0w9ZS5pbnN0YW5jZSxJZS5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUoZSx0PTApe2lmKCFMKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBJPWUuYnl0ZUxlbmd0aCxyPUwuZXhwb3J0cy5tYWxsb2MoSSk7cmUuc2V0KGUsciksdD10fHxOdW1iZXIoTC5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUocixJKSk7bGV0IGk9TC5leHBvcnRzLm1hbGxvYyh0KSxnPUwuZXhwb3J0cy5aU1REX2RlY29tcHJlc3MoaSx0LHIsSSksbj1yZS5zbGljZShpLGkrZyk7cmV0dXJuIEwuZXhwb3J0cy5mcmVlKHIpLEwuZXhwb3J0cy5mcmVlKGkpLG59fSxldD0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciB0dD1uZXcgR0EsSXQ9ITE7YXN5bmMgZnVuY3Rpb24gREkoQSxlKXtsZXQgdD1udWxsO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IEk9YCR7dH0ud2FzbWAscj1hd2FpdCBSQS5nZXQoYCR7SX0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KTtJdHx8KGF3YWl0IHR0LmluaXQoKSxJdD0hMCk7bGV0IGc9dHQuZGVjb2RlKG5ldyBVaW50OEFycmF5KHIuZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6Z30pfXZhciBydD1ESTt2YXIgVUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiB5SShBLGUpe2xldCB0PUEsST1BLHI9bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYodD1uZXcgVVJMKEEuaHJlZiksST10LmhyZWYpLFVBLmhhcyhJKXx8VUEuc2V0KEksYXdhaXQgcnQodCxlKSkscj1VQS5nZXQoSSkscn12YXIgRz15STt2YXIgd0k9bmV3IE1hcChbWyJpbWFnZS9qcGVnIiwiSlBFR0ltYWdlSU8iXSxbImltYWdlL3BuZyIsIlBOR0ltYWdlSU8iXSxbImltYWdlL3RpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiaW1hZ2UveC1tcy1ibXAiLCJCTVBJbWFnZUlPIl0sWyJpbWFnZS94LWJtcCIsIkJNUEltYWdlSU8iXSxbImltYWdlL2JtcCIsIkJNUEltYWdlSU8iXSxbImFwcGxpY2F0aW9uL2RpY29tIiwiR0RDTUltYWdlSU8iXV0pLGllPXdJO3ZhciBwST1uZXcgTWFwKFtbImJtcCIsIkJNUEltYWdlSU8iXSxbIkJNUCIsIkJNUEltYWdlSU8iXSxbImRjbSIsIkdEQ01JbWFnZUlPIl0sWyJEQ00iLCJHRENNSW1hZ2VJTyJdLFsiZ2lwbCIsIkdpcGxJbWFnZUlPIl0sWyJnaXBsLmd6IiwiR2lwbEltYWdlSU8iXSxbImhkZjUiLCJIREY1SW1hZ2VJTyJdLFsianBnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRyIsIkpQRUdJbWFnZUlPIl0sWyJqcGVnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRUciLCJKUEVHSW1hZ2VJTyJdLFsiaXdpIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yLnpzdCIsIldhc21ac3RkSW1hZ2VJTyJdLFsibHNtIiwiTFNNSW1hZ2VJTyJdLFsibW5jIiwiTUlOQ0ltYWdlSU8iXSxbIk1OQyIsIk1JTkNJbWFnZUlPIl0sWyJtbmMuZ3oiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DLkdaIiwiTUlOQ0ltYWdlSU8iXSxbIm1uYzIiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DMiIsIk1JTkNJbWFnZUlPIl0sWyJtZ2giLCJNR0hJbWFnZUlPIl0sWyJtZ3oiLCJNR0hJbWFnZUlPIl0sWyJtZ2guZ3oiLCJNR0hJbWFnZUlPIl0sWyJtaGEiLCJNZXRhSW1hZ2VJTyJdLFsibWhkIiwiTWV0YUltYWdlSU8iXSxbIm1yYyIsIk1SQ0ltYWdlSU8iXSxbIm5pYSIsIk5pZnRpSW1hZ2VJTyJdLFsibmlpIiwiTmlmdGlJbWFnZUlPIl0sWyJuaWkuZ3oiLCJOaWZ0aUltYWdlSU8iXSxbImhkciIsIk5pZnRpSW1hZ2VJTyJdLFsibnJyZCIsIk5ycmRJbWFnZUlPIl0sWyJOUlJEIiwiTnJyZEltYWdlSU8iXSxbIm5oZHIiLCJOcnJkSW1hZ2VJTyJdLFsiTkhEUiIsIk5ycmRJbWFnZUlPIl0sWyJwbmciLCJQTkdJbWFnZUlPIl0sWyJQTkciLCJQTkdJbWFnZUlPIl0sWyJwaWMiLCJCaW9SYWRJbWFnZUlPIl0sWyJQSUMiLCJCaW9SYWRJbWFnZUlPIl0sWyJ0aWYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGIiwiVElGRkltYWdlSU8iXSxbInRpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGRiIsIlRJRkZJbWFnZUlPIl0sWyJ2dGsiLCJWVEtJbWFnZUlPIl0sWyJWVEsiLCJWVEtJbWFnZUlPIl0sWyJpc3EiLCJTY2FuY29JbWFnZUlPIl0sWyJJU1EiLCJTY2FuY29JbWFnZUlPIl0sWyJmZGYiLCJGREZJbWFnZUlPIl0sWyJGREYiLCJGREZJbWFnZUlPIl1dKSxnZT1wSTtmdW5jdGlvbiBGSShBKXtsZXQgZT1BLnNsaWNlKChBLmxhc3RJbmRleE9mKCIuIiktMT4+PjApKzIpO2lmKGUudG9Mb3dlckNhc2UoKT09PSJneiIpe2xldCB0PUEuc2xpY2UoMCwtMykubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoZS50b0xvd2VyQ2FzZSgpPT09ImNib3IiKXtsZXQgdD1BLnNsaWNlKDAsLTUpLmxhc3RJbmRleE9mKCIuIik7ZT1BLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKGUudG9Mb3dlckNhc2UoKT09PSJ6c3QiKXtsZXQgdD1BLnNsaWNlKDAsLTEwKS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihlLnRvTG93ZXJDYXNlKCk9PT0iemlwIil7bGV0IHQ9QS5zbGljZSgwLC00KS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9cmV0dXJuIGV9dmFyIGtBPUZJO3ZhciBTST1bIlBOR0ltYWdlSU8iLCJNZXRhSW1hZ2VJTyIsIlRJRkZJbWFnZUlPIiwiTmlmdGlJbWFnZUlPIiwiSlBFR0ltYWdlSU8iLCJOcnJkSW1hZ2VJTyIsIlZUS0ltYWdlSU8iLCJCTVBJbWFnZUlPIiwiSERGNUltYWdlSU8iLCJNSU5DSW1hZ2VJTyIsIk1SQ0ltYWdlSU8iLCJMU01JbWFnZUlPIiwiTUdISW1hZ2VJTyIsIkJpb1JhZEltYWdlSU8iLCJHaXBsSW1hZ2VJTyIsIkdFQWR3SW1hZ2VJTyIsIkdFNEltYWdlSU8iLCJHRTVJbWFnZUlPIiwiR0RDTUltYWdlSU8iLCJTY2FuY29JbWFnZUlPIiwiRkRGSW1hZ2VJTyIsIldhc21JbWFnZUlPIiwiV2FzbVpzdGRJbWFnZUlPIl0sTEE9U0k7dmFyIE5JPXtUZXh0RmlsZToiSW50ZXJmYWNlVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkludGVyZmFjZUJpbmFyeUZpbGUiLFRleHRTdHJlYW06IkludGVyZmFjZVRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiSW50ZXJmYWNlQmluYXJ5U3RyZWFtIixJbWFnZToiSW50ZXJmYWNlSW1hZ2UiLE1lc2g6IkludGVyZmFjZU1lc2giLFBvbHlEYXRhOiJJbnRlcmZhY2VQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6IkludGVyZmFjZUpzb25Db21wYXRpYmxlIn0sdT1OSTt2YXIgUkk9e1RleHQ6IlRleHQiLEJpbmFyeToiQmluYXJ5IixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2gifSxTPVJJO3ZhciBHST17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEY9R0k7dmFyIFVJPXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxUPVVJO2Z1bmN0aW9uIGtJKEEsZSl7bGV0IHQ9bnVsbDtzd2l0Y2goQSl7Y2FzZSBGLlVJbnQ4Ont0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ4Ont0PW5ldyBJbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQxNjp7dD1uZXcgVWludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDE2Ont0PW5ldyBJbnQxNkFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50MzI6e3Q9bmV3IFVpbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQzMjp7dD1uZXcgSW50MzJBcnJheShlKTticmVha31jYXNlIEYuVUludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdVaW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdVaW50NjRBcnJheShlKTp0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnSW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdJbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBULkZsb2F0MzI6e3Q9bmV3IEZsb2F0MzJBcnJheShlKTticmVha31jYXNlIFQuRmxvYXQ2NDp7dD1uZXcgRmxvYXQ2NEFycmF5KGUpO2JyZWFrfWNhc2UibnVsbCI6e3Q9bnVsbDticmVha31jYXNlIG51bGw6e3Q9bnVsbDticmVha31kZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVHlwZSBpcyBub3Qgc3VwcG9ydGVkIGFzIGEgVHlwZWRBcnJheSIpfXJldHVybiB0fXZhciBkPWtJO3ZhciBvdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixpdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoQSxlKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3BlbihlLHQuZmxhZ3MpLGk9QS5mc19zdGF0KGUpLnNpemUsZz1udWxsO290P2c9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGkpOmc9bmV3IEFycmF5QnVmZmVyKGkpO2xldCBuPW5ldyBVaW50OEFycmF5KGcpO3JldHVybiBBLmZzX3JlYWQoSSxuLDAsaSwwKSxBLmZzX2Nsb3NlKEkpLG59ZnVuY3Rpb24gbnQoQSxlLHQpe2xldCBJPW51bGw7b3Q/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ST1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksaT1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsZSx0KTtyZXR1cm4gci5zZXQoaSkscn1mdW5jdGlvbiB5KEEsZSx0LEkpe2xldCByPTA7cmV0dXJuIGUhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEksZS5idWZmZXIuYnl0ZUxlbmd0aF0pLEEuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShlLmJ1ZmZlcikscikpLHJ9ZnVuY3Rpb24gVihBLGUsdCl7bGV0IEk9SlNPTi5zdHJpbmdpZnkoZSkscj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsSS5sZW5ndGhdKTtBLndyaXRlQXNjaWlUb01lbW9yeShJLHIsITEpfWZ1bmN0aW9uIE4oQSxlLHQsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksaT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxnPW50KEEscixpKTtyZXR1cm4gZChJLGcuYnVmZmVyKX1mdW5jdGlvbiBvZShBLGUpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsZV0pLEk9QS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKEkpfWZ1bmN0aW9uIExJKEEsZSx0LEkpe0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihvLEIpe3ZhciBjO3N3aXRjaChvLnR5cGUpe2Nhc2UgdS5UZXh0U3RyZWFtOntsZXQgYT1pdC5lbmNvZGUoby5kYXRhLmRhdGEpLEM9eShBLGEsQiwwKSxRPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07VihBLFEsQik7YnJlYWt9Y2FzZSB1Lkpzb25Db21wYXRpYmxlOntsZXQgYT1pdC5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoby5kYXRhKSksQz15KEEsYSxCLDApLFE9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTtWKEEsUSxCKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgYT1vLmRhdGEuZGF0YSxDPXkoQSxhLEIsMCksUT17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1YoQSxRLEIpO2JyZWFrfWNhc2UgdS5UZXh0RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgdS5CaW5hcnlGaWxlOntBLmZzX3dyaXRlRmlsZShvLmRhdGEucGF0aCxvLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSB1LkltYWdlOntsZXQgYT1vLmRhdGEsQz15KEEsYS5kYXRhLEIsMCksUT15KEEsYS5kaXJlY3Rpb24sQiwxKSxmPXR5cGVvZigoYz1hLm1ldGFkYXRhKT09PW51bGx8fGM9PT12b2lkIDA/dm9pZCAwOmMuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20oYS5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLG09e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLHNpemU6YS5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsbWV0YWRhdGE6Zn07VihBLG0sQik7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBhPW8uZGF0YSxDPXkoQSxhLnBvaW50cyxCLDApLFE9eShBLGEuY2VsbHMsQiwxKSxmPXkoQSxhLnBvaW50RGF0YSxCLDIpLG09eShBLGEuY2VsbERhdGEsQiwzKSx3PXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YH07VihBLHcsQik7YnJlYWt9Y2FzZSB1LlBvbHlEYXRhOntsZXQgYT1vLmRhdGEsQz15KEEsYS5wb2ludHMsQiwwKSxRPXkoQSxhLnZlcnRpY2VzLEIsMSksZj15KEEsYS5saW5lcyxCLDIpLG09eShBLGEucG9seWdvbnMsQiwzKSx3PXkoQSxhLnRyaWFuZ2xlU3RyaXBzLEIsNCksTz15KEEsYS5wb2ludERhdGEsQiw1KSxLPXkoQSxhLnBvaW50RGF0YSxCLDYpLEpBPXtwb2x5RGF0YVR5cGU6YS5wb2x5RGF0YVR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsdmVydGljZXNCdWZmZXJTaXplOmEudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGxpbmVzQnVmZmVyU2l6ZTphLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxwb2x5Z29uc0J1ZmZlclNpemU6YS5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOmEudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7d31gLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke099YCxudW1iZXJPZkNlbGxQaXhlbHM6YS5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtLfWB9O1YoQSxKQSxCKTticmVha31jYXNlIFMuVGV4dDp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkJpbmFyeTp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkltYWdlOntsZXQgYT1vLmRhdGEsQz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTphLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoQykpLGEuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5kYXRhLmJ1ZmZlcikpLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShhLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFMuTWVzaDp7bGV0IGE9by5kYXRhLEM9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZX07aWYoQS5mc19ta2RpcnMoYCR7by5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShDKSksQy5udW1iZXJPZlBvaW50cz4wKXtpZihhLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5wb2ludHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKGEucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShhLnBvaW50RGF0YS5idWZmZXIpKX1pZihDLm51bWJlck9mQ2VsbHM+MCl7aWYoYS5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYoYS5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLEEucmVzZXRNb2R1bGVTdGRvdXQoKSxBLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IHI9QS5zdGFja1NhdmUoKSxpPTA7dHJ5e2k9QS5jYWxsTWFpbihlLnNsaWNlKCkpfWNhdGNoKG8pe3Rocm93IHR5cGVvZiBvPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsQS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsQS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIEEuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsQS5nZXRFeGNlcHRpb25NZXNzYWdlKG8pKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLG99ZmluYWxseXtBLnN0YWNrUmVzdG9yZShyKX1sZXQgZz1BLmdldE1vZHVsZVN0ZG91dCgpLG49QS5nZXRNb2R1bGVTdGRlcnIoKSxFPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZpPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKG8sQil7bGV0IGM9bnVsbDtzd2l0Y2goby50eXBlKXtjYXNlIHUuVGV4dFN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLFEpO2M9e2RhdGE6Z3QuZGVjb2RlKGYpfTticmVha31jYXNlIHUuSnNvbkNvbXBhdGlibGU6e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksZj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsQyxRKTtjPUpTT04ucGFyc2UoZ3QuZGVjb2RlKGYpKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pO2M9e2RhdGE6bnQoQSxDLFEpfTticmVha31jYXNlIHUuVGV4dEZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpBLmZzX3JlYWRGaWxlKG8uZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSB1LkJpbmFyeUZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpIKEEsby5kYXRhLnBhdGgpfTticmVha31jYXNlIHUuSW1hZ2U6e2xldCBDPW9lKEEsQik7Qy5kYXRhPU4oQSxCLDAsQy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQy5kaXJlY3Rpb249TihBLEIsMSxULkZsb2F0NjQpLEMubWV0YWRhdGE9bmV3IE1hcChDLm1ldGFkYXRhKSxjPUM7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkMucG9pbnRzPWQoQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbHM+MD9DLmNlbGxzPU4oQSxCLDEsQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qy5jZWxscz1kKEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiwyLEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPWQoQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1OKEEsQiwzLEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGM9QzticmVha31jYXNlIHUuUG9seURhdGE6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsVC5GbG9hdDMyKTpDLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEMudmVydGljZXNCdWZmZXJTaXplPjA/Qy52ZXJ0aWNlcz1OKEEsQiwxLEYuVUludDMyKTpDLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxDLmxpbmVzQnVmZmVyU2l6ZT4wP0MubGluZXM9TihBLEIsMixGLlVJbnQzMik6Qy5saW5lcz1uZXcgVWludDMyQXJyYXksQy5wb2x5Z29uc0J1ZmZlclNpemU+MD9DLnBvbHlnb25zPU4oQSxCLDMsRi5VSW50MzIpOkMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qy50cmlhbmdsZVN0cmlwcz1OKEEsQiw0LEYuVUludDMyKTpDLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiw1LEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpDLnBvaW50RGF0YT1kKEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxQaXhlbHM+MD9DLmNlbGxEYXRhPU4oQSxCLDYsQy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxjPUM7YnJlYWt9Y2FzZSBTLlRleHQ6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtjPUEuZnNfcmVhZEZpbGUoby5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFMuQmluYXJ5OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Yz1IKEEsby5wYXRoKTticmVha31jYXNlIFMuSW1hZ2U6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgQz1BLmZzX3JlYWRGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLFE9SlNPTi5wYXJzZShDKSxmPUgoQSxgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtRLmRhdGE9ZChRLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGYuYnVmZmVyKTtsZXQgbT1IKEEsYCR7by5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtRLmRpcmVjdGlvbj1kKFQuRmxvYXQ2NCxtLmJ1ZmZlciksYz1RO2JyZWFrfWNhc2UgUy5NZXNoOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEM9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxRPUpTT04ucGFyc2UoQyk7aWYoUS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtRLnBvaW50cz1kKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnRzPWQoUS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihRLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7US5wb2ludERhdGE9ZChRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnREYXRhPWQoUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKFEubnVtYmVyT2ZDZWxscz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO1EuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoUS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtRLmNlbGxEYXRhPWQoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbERhdGE9ZChRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtjPVE7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgYT17dHlwZTpvLnR5cGUsZGF0YTpjfTtFLnB1c2goYSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6ZyxzdGRlcnI6bixvdXRwdXRzOkV9fXZhciB6PUxJO3ZhciBvQT1mdW5jdGlvbihBKXtyZXR1cm4gdGhpcyBpbnN0YW5jZW9mIG9BPyh0aGlzLnY9QSx0aGlzKTpuZXcgb0EoQSl9LE9JPWZ1bmN0aW9uKEEsZSx0KXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIEk9dC5hcHBseShBLGV8fFtdKSxyLGk9W107cmV0dXJuIHI9e30sZygibmV4dCIpLGcoInRocm93IiksZygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scjtmdW5jdGlvbiBnKGEpe0lbYV0mJihyW2FdPWZ1bmN0aW9uKEMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihRLGYpe2kucHVzaChbYSxDLFEsZl0pPjF8fG4oYSxDKX0pfSl9ZnVuY3Rpb24gbihhLEMpe3RyeXtFKElbYV0oQykpfWNhdGNoKFEpe2MoaVswXVszXSxRKX19ZnVuY3Rpb24gRShhKXthLnZhbHVlIGluc3RhbmNlb2Ygb0E/UHJvbWlzZS5yZXNvbHZlKGEudmFsdWUudikudGhlbihvLEIpOmMoaVswXVsyXSxhKX1mdW5jdGlvbiBvKGEpe24oIm5leHQiLGEpfWZ1bmN0aW9uIEIoYSl7bigidGhyb3ciLGEpfWZ1bmN0aW9uIGMoYSxDKXthKEMpLGkuc2hpZnQoKSxpLmxlbmd0aCYmbihpWzBdWzBdLGlbMF1bMV0pfX0sSkk9ZnVuY3Rpb24oQSl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBlPUFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdLHQ7cmV0dXJuIGU/ZS5jYWxsKEEpOihBPXR5cGVvZiBfX3ZhbHVlcz09ImZ1bmN0aW9uIj9fX3ZhbHVlcyhBKTpBW1N5bWJvbC5pdGVyYXRvcl0oKSx0PXt9LEkoIm5leHQiKSxJKCJ0aHJvdyIpLEkoInJldHVybiIpLHRbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHQpO2Z1bmN0aW9uIEkoaSl7dFtpXT1BW2ldJiZmdW5jdGlvbihnKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obixFKXtnPUFbaV0oZykscihuLEUsZy5kb25lLGcudmFsdWUpfSl9fWZ1bmN0aW9uIHIoaSxnLG4sRSl7UHJvbWlzZS5yZXNvbHZlKEUpLnRoZW4oZnVuY3Rpb24obyl7aSh7dmFsdWU6byxkb25lOm59KX0sZyl9fTtmdW5jdGlvbiBNSShBKXtyZXR1cm4gT0kodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24qKCl7Zm9yKGxldCB0PTA7dDxMQS5sZW5ndGg7dCsrKXtsZXQgST1MQVt0XSsiLXJlYWQtaW1hZ2UiLHI9eWllbGQgb0EoRyhJLEEuY29uZmlnLmltYWdlSU9VcmwpKTt5aWVsZCB5aWVsZCBvQShyKX19KX1hc3luYyBmdW5jdGlvbiBiSShBLGUpe3ZhciB0LEk7aWYoQS5taW1lVHlwZSYmaWUuaGFzKEEubWltZVR5cGUpKXtsZXQgbj1pZS5nZXQoQS5taW1lVHlwZSkrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLmltYWdlSU9VcmwpfWxldCByPWtBKEEuZmlsZU5hbWUpO2lmKGdlLmhhcyhyKSl7bGV0IG49Z2UuZ2V0KHIpK2U7cmV0dXJuIGF3YWl0IEcobixBLmNvbmZpZy5pbWFnZUlPVXJsKX1mb3IobGV0IG49MDtuPExBLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsSkkoTUkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBuZT1iSTt2YXIgSEk9bmV3IE1hcChbXSksYWU9SEk7dmFyIFlJPW5ldyBNYXAoW1sidnRrIiwiVlRLUG9seURhdGFNZXNoSU8iXSxbIlZUSyIsIlZUS1BvbHlEYXRhTWVzaElPIl0sWyJieXUiLCJCWVVNZXNoSU8iXSxbIkJZVSIsIkJZVU1lc2hJTyJdLFsiZnNhIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIl0sWyJGU0EiLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iXSxbImZzYiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIkZTQiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIm9iaiIsIk9CSk1lc2hJTyJdLFsiT0JKIiwiT0JKTWVzaElPIl0sWyJvZmYiLCJPRkZNZXNoSU8iXSxbIk9GRiIsIk9GRk1lc2hJTyJdLFsic3RsIiwiU1RMTWVzaElPIl0sWyJTVEwiLCJTVExNZXNoSU8iXSxbInN3YyIsIlNXQ01lc2hJTyJdLFsiU1dDIiwiU1dDTWVzaElPIl0sWyJpd20iLCJXYXNtTWVzaElPIl0sWyJpd20uY2JvciIsIldhc21NZXNoSU8iXSxbIml3bS5jYm9yLnpzdCIsIldhc21ac3RkTWVzaElPIl1dKSxzZT1ZSTt2YXIgcUk9WyJCWVVNZXNoSU8iLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIiwiT0JKTWVzaElPIiwiT0ZGTWVzaElPIiwiU1RMTWVzaElPIiwiU1dDTWVzaElPIiwiVlRLUG9seURhdGFNZXNoSU8iLCJXYXNtTWVzaElPIiwiV2FzbVpzdGRNZXNoSU8iXSxPQT1xSTt2YXIgbkE9ZnVuY3Rpb24oQSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBuQT8odGhpcy52PUEsdGhpcyk6bmV3IG5BKEEpfSxUST1mdW5jdGlvbihBLGUsdCl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBJPXQuYXBwbHkoQSxlfHxbXSkscixpPVtdO3JldHVybiByPXt9LGcoIm5leHQiKSxnKCJ0aHJvdyIpLGcoInJldHVybiIpLHJbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHI7ZnVuY3Rpb24gZyhhKXtJW2FdJiYoclthXT1mdW5jdGlvbihDKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oUSxmKXtpLnB1c2goW2EsQyxRLGZdKT4xfHxuKGEsQyl9KX0pfWZ1bmN0aW9uIG4oYSxDKXt0cnl7RShJW2FdKEMpKX1jYXRjaChRKXtjKGlbMF1bM10sUSl9fWZ1bmN0aW9uIEUoYSl7YS52YWx1ZSBpbnN0YW5jZW9mIG5BP1Byb21pc2UucmVzb2x2ZShhLnZhbHVlLnYpLnRoZW4obyxCKTpjKGlbMF1bMl0sYSl9ZnVuY3Rpb24gbyhhKXtuKCJuZXh0IixhKX1mdW5jdGlvbiBCKGEpe24oInRocm93IixhKX1mdW5jdGlvbiBjKGEsQyl7YShDKSxpLnNoaWZ0KCksaS5sZW5ndGgmJm4oaVswXVswXSxpWzBdWzFdKX19LEtJPWZ1bmN0aW9uKEEpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgZT1BW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSx0O3JldHVybiBlP2UuY2FsbChBKTooQT10eXBlb2YgX192YWx1ZXM9PSJmdW5jdGlvbiI/X192YWx1ZXMoQSk6QVtTeW1ib2wuaXRlcmF0b3JdKCksdD17fSxJKCJuZXh0IiksSSgidGhyb3ciKSxJKCJyZXR1cm4iKSx0W1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0KTtmdW5jdGlvbiBJKGkpe3RbaV09QVtpXSYmZnVuY3Rpb24oZyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4sRSl7Zz1BW2ldKGcpLHIobixFLGcuZG9uZSxnLnZhbHVlKX0pfX1mdW5jdGlvbiByKGksZyxuLEUpe1Byb21pc2UucmVzb2x2ZShFKS50aGVuKGZ1bmN0aW9uKG8pe2koe3ZhbHVlOm8sZG9uZTpufSl9LGcpfX07ZnVuY3Rpb24geEkoQSl7cmV0dXJuIFRJKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKigpe2ZvcihsZXQgdD0wO3Q8T0EubGVuZ3RoO3QrKyl7bGV0IEk9T0FbdF0rIi1yZWFkLW1lc2giLHI9eWllbGQgbkEoRyhJLEEuY29uZmlnLm1lc2hJT1VybCkpO3lpZWxkIHlpZWxkIG5BKHIpfX0pfWFzeW5jIGZ1bmN0aW9uIFBJKEEsZSl7dmFyIHQsSTtpZihBLm1pbWVUeXBlJiZhZS5oYXMoQS5taW1lVHlwZSkpe2xldCBuPWFlLmdldChBLm1pbWVUeXBlKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1sZXQgcj1rQShBLmZpbGVOYW1lKTtpZihzZS5oYXMocikpe2xldCBuPXNlLmdldChyKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1mb3IobGV0IG49MDtuPE9BLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsS0koeEkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBDZT1QSTt2YXIgV0k9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIGpJKEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCB0PTA7dDxBLmxlbmd0aDt0Kyspe2xldCBJPVpJKEFbdF0pO0khPT1udWxsJiZlLnB1c2goSSl9cmV0dXJuIGV9ZnVuY3Rpb24gWkkoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgZT1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD9lPUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKGU9QSksV0kmJmUgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmV9dmFyIGF0PWpJO2Z1bmN0aW9uIF9JKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciBCZT1fSTtmdW5jdGlvbiBWSShBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgUWU9Vkk7ZnVuY3Rpb24gekkoQSl7cmV0dXJuW0EucG9pbnRzLEEudmVydGljZXMsQS5saW5lcyxBLnBvbHlnb25zLEEudHJpYW5nbGVTdHJpcHMsQS5wb2ludERhdGEsQS5jZWxsRGF0YV19dmFyIHN0PXpJO2FzeW5jIGZ1bmN0aW9uIFhJKEEsZSx0LEkpe2xldCByPXooQSxlLHQsSSksaT1bXTtyZXR1cm4gci5vdXRwdXRzJiZyLm91dHB1dHMuZm9yRWFjaChmdW5jdGlvbihnKXtpZihnLnR5cGU9PT11LkJpbmFyeVN0cmVhbXx8Zy50eXBlPT09dS5CaW5hcnlGaWxlKXtsZXQgbj1nLmRhdGE7aS5wdXNoKG4pfWVsc2UgaWYoZy50eXBlPT09dS5JbWFnZSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5CZShuKSl9ZWxzZSBpZihnLnR5cGU9PT11Lk1lc2gpe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uUWUobikpfWVsc2UgaWYoZy50eXBlPT09dS5Qb2x5RGF0YSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5zdChuKSl9ZWxzZSBpZihnLnR5cGU9PT1TLkJpbmFyeSl7bGV0IG49Zy5kYXRhO2kucHVzaChuKX1lbHNlIGlmKGcudHlwZT09PVMuSW1hZ2Upe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uQmUobikpfWVsc2UgaWYoZy50eXBlPT09Uy5NZXNoKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLlFlKG4pKX19KSxIQShyLGF0KGkpKX12YXIgWT1YSTt2YXIgdkk9e21lc2hUb1BvbHlEYXRhOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkpe2xldCByPWF3YWl0IEcoIm1lc2gtdG8tcG9seWRhdGEiLEEubWVzaElPVXJsKTtyZXR1cm4gWShyLGUsdCxJKX0scG9seURhdGFUb01lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSl7bGV0IHI9YXdhaXQgRygicG9seWRhdGEtdG8tbWVzaCIsQS5tZXNoSU9VcmwpO3JldHVybiBZKHIsZSx0LEkpfSxyZWFkSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi1yZWFkLWltYWdlIik7cmV0dXJuIFkoZyxJLHIsaSl9LHdyaXRlSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1pbWFnZSIpO3JldHVybiBZKGcsSSxyLGkpfSxyZWFkTWVzaDphc3luYyBmdW5jdGlvbihBLGUsdCxJLHIsaSl7bGV0IGc9YXdhaXQgQ2Uoe2ZpbGVOYW1lOnQsbWltZVR5cGU6ZSxjb25maWc6QSxhcmdzOkksb3V0cHV0czpyLGlucHV0czppfSwiLXJlYWQtbWVzaCIpO3JldHVybiBZKGcsSSxyLGkpfSx3cml0ZU1lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IENlKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1tZXNoIik7cmV0dXJuIFkoZyxJLHIsaSl9LHJ1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz10eXBlb2YgQVt0XT4idSI/dDpBW3RdLG49YXdhaXQgRyhlLGcpO3JldHVybiBZKG4sSSxyLGkpfX07RUEodkkpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7cHIodXIpO2V4cG9ydHtIQSBhcyBiaW9SYWRSZWFkSW1hZ2UsWUEgYXMgYmlvUmFkV3JpdGVJbWFnZSxPQSBhcyBibXBSZWFkSW1hZ2UsVUEgYXMgYm1wV3JpdGVJbWFnZSx0dCBhcyBmZGZSZWFkSW1hZ2UsZW8gYXMgZmRmV3JpdGVJbWFnZSxYQSBhcyBnZGNtUmVhZEltYWdlLCRBIGFzIGdkY21Xcml0ZUltYWdlLF9BIGFzIGdlNFJlYWRJbWFnZSx6QSBhcyBnZTRXcml0ZUltYWdlLFZBIGFzIGdlNVJlYWRJbWFnZSxaQSBhcyBnZTVXcml0ZUltYWdlLEtBIGFzIGdlQWR3UmVhZEltYWdlLGpBIGFzIGdlQWR3V3JpdGVJbWFnZSx5IGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLEMgYXMgZ2V0UGlwZWxpbmVzQmFzZVVybCxxQSBhcyBnaXBsUmVhZEltYWdlLHZBIGFzIGdpcGxXcml0ZUltYWdlLFNBIGFzIGhkZjVSZWFkSW1hZ2UsV0EgYXMgaGRmNVdyaXRlSW1hZ2Usd0EgYXMganBlZ1JlYWRJbWFnZSxSQSBhcyBqcGVnV3JpdGVJbWFnZSxUQSBhcyBsc21SZWFkSW1hZ2UsSkEgYXMgbHNtV3JpdGVJbWFnZSxCQSBhcyBtZXRhUmVhZEltYWdlLENBIGFzIG1ldGFXcml0ZUltYWdlLExBIGFzIG1naFJlYWRJbWFnZSxNQSBhcyBtZ2hXcml0ZUltYWdlLE5BIGFzIG1pbmNSZWFkSW1hZ2UsUEEgYXMgbWluY1dyaXRlSW1hZ2UseEEgYXMgbXJjUmVhZEltYWdlLEdBIGFzIG1yY1dyaXRlSW1hZ2UsUUEgYXMgbmlmdGlSZWFkSW1hZ2UsaEEgYXMgbmlmdGlXcml0ZUltYWdlLGJBIGFzIG5ycmRSZWFkSW1hZ2Usa0EgYXMgbnJyZFdyaXRlSW1hZ2UsY0EgYXMgcG5nUmVhZEltYWdlLGRBIGFzIHBuZ1dyaXRlSW1hZ2UsbnQgYXMgcmVhZEltYWdlLFZhIGFzIHJlYWRJbWFnZUZpbGVTZXJpZXMsZXQgYXMgc2NhbmNvUmVhZEltYWdlLEF0IGFzIHNjYW5jb1dyaXRlSW1hZ2UscHIgYXMgc2V0UGlwZWxpbmVXb3JrZXJVcmwscGwgYXMgc2V0UGlwZWxpbmVzQmFzZVVybCx5QSBhcyB0aWZmUmVhZEltYWdlLEVBIGFzIHRpZmZXcml0ZUltYWdlLERBIGFzIHZ0a1JlYWRJbWFnZSxGQSBhcyB2dGtXcml0ZUltYWdlLHJ0IGFzIHdhc21SZWFkSW1hZ2UsaXQgYXMgd2FzbVdyaXRlSW1hZ2UsYXQgYXMgd2FzbVpzdGRSZWFkSW1hZ2Usb3QgYXMgd2FzbVpzdGRXcml0ZUltYWdlLFhhIGFzIHdyaXRlSW1hZ2V9OwovKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOgoKY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczoKICAoKioKICAgKiBAbGljZW5zZQogICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMKICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMAogICAqKQoqLwo=""" +default_js_module = """data:text/javascript;base64,dmFyIGZyPSIxLjAuMC1iLjE1NCIscmU9ZnI7dmFyIGNyPXtwaXBlbGluZVdvcmtlclVybDpgaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9pdGstd2FzbUAke3JlfS9kaXN0L2NvcmUvd2ViLXdvcmtlcnMvYnVuZGxlcy9waXBlbGluZS5taW4ud29ya2VyLmpzYCxpbWFnZUlPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1pbWFnZS1pb0Ake3JlfWAsbWVzaElPVXJsOmBodHRwczovL2Nkbi5qc2RlbGl2ci5uZXQvbnBtL2l0ay1tZXNoLWlvQCR7cmV9YCxwaXBlbGluZXNVcmw6YGh0dHBzOi8vY2RuLmpzZGVsaXZyLm5ldC9ucG0vaXRrLXdhc21AJHtyZX0vZGlzdC9waXBlbGluZXNgfSx2PWNyO3ZhciBkcj17VGV4dEZpbGU6IkludGVyZmFjZVRleHRGaWxlIixCaW5hcnlGaWxlOiJJbnRlcmZhY2VCaW5hcnlGaWxlIixUZXh0U3RyZWFtOiJJbnRlcmZhY2VUZXh0U3RyZWFtIixCaW5hcnlTdHJlYW06IkludGVyZmFjZUJpbmFyeVN0cmVhbSIsSW1hZ2U6IkludGVyZmFjZUltYWdlIixNZXNoOiJJbnRlcmZhY2VNZXNoIixQb2x5RGF0YToiSW50ZXJmYWNlUG9seURhdGEiLEpzb25Db21wYXRpYmxlOiJJbnRlcmZhY2VKc29uQ29tcGF0aWJsZSJ9LG09ZHI7dmFyIEJyPXtJbnQ4OiJpbnQ4IixVSW50ODoidWludDgiLEludDE2OiJpbnQxNiIsVUludDE2OiJ1aW50MTYiLEludDMyOiJpbnQzMiIsVUludDMyOiJ1aW50MzIiLEludDY0OiJpbnQ2NCIsVUludDY0OiJ1aW50NjQiLFNpemVWYWx1ZVR5cGU6InVpbnQ2NCIsSWRlbnRpZmllclR5cGU6InVpbnQ2NCIsSW5kZXhWYWx1ZVR5cGU6ImludDY0IixPZmZzZXRWYWx1ZVR5cGU6ImludDY0In0sUT1Ccjt2YXIgQ3I9e0Zsb2F0MzI6ImZsb2F0MzIiLEZsb2F0NjQ6ImZsb2F0NjQiLFNwYWNlUHJlY2lzaW9uVHlwZToiZmxvYXQ2NCJ9LFM9Q3I7dmFyIHlyPXtUZXh0OiJUZXh0IixCaW5hcnk6IkJpbmFyeSIsSW1hZ2U6IkltYWdlIixNZXNoOiJNZXNoIn0sVz15cjt2YXIgRXI9e1Vua25vd246IlVua25vd24iLFNjYWxhcjoiU2NhbGFyIixSR0I6IlJHQiIsUkdCQToiUkdCQSIsT2Zmc2V0OiJPZmZzZXQiLFZlY3RvcjoiVmVjdG9yIixQb2ludDoiUG9pbnQiLENvdmFyaWFudFZlY3RvcjoiQ292YXJpYW50VmVjdG9yIixTeW1tZXRyaWNTZWNvbmRSYW5rVGVuc29yOiJTeW1tZXRyaWNTZWNvbmRSYW5rVGVuc29yIixEaWZmdXNpb25UZW5zb3IzRDoiRGlmZnVzaW9uVGVuc29yM0QiLENvbXBsZXg6IkNvbXBsZXgiLEZpeGVkQXJyYXk6IkZpeGVkQXJyYXkiLEFycmF5OiJBcnJheSIsTWF0cml4OiJNYXRyaXgiLFZhcmlhYmxlTGVuZ3RoVmVjdG9yOiJWYXJpYWJsZUxlbmd0aFZlY3RvciIsVmFyaWFibGVTaXplTWF0cml4OiJWYXJpYWJsZVNpemVNYXRyaXgifSx1ZT1FcjtmdW5jdGlvbiBRcihlLEEsdCxyLGEpe2Vbcit0KkFdPWF9dmFyIHN0PVFyO3ZhciBOZT1jbGFzc3tjb25zdHJ1Y3RvcihBPTIsdD1RLlVJbnQ4LHI9dWUuU2NhbGFyLGE9MSl7dGhpcy5kaW1lbnNpb249QSx0aGlzLmNvbXBvbmVudFR5cGU9dCx0aGlzLnBpeGVsVHlwZT1yLHRoaXMuY29tcG9uZW50cz1hfX0sSXQ9TmU7dmFyIFBlPWNsYXNze2NvbnN0cnVjdG9yKEE9bmV3IEl0KXt0aGlzLmltYWdlVHlwZT1BLHRoaXMubmFtZT0iaW1hZ2UiO2xldCB0PUEuZGltZW5zaW9uO3RoaXMub3JpZ2luPW5ldyBBcnJheSh0KSx0aGlzLm9yaWdpbi5maWxsKDApLHRoaXMuc3BhY2luZz1uZXcgQXJyYXkodCksdGhpcy5zcGFjaW5nLmZpbGwoMSksdGhpcy5kaXJlY3Rpb249bmV3IEZsb2F0NjRBcnJheSh0KnQpLHRoaXMuZGlyZWN0aW9uLmZpbGwoMCk7Zm9yKGxldCByPTA7cjx0O3IrKylzdCh0aGlzLmRpcmVjdGlvbix0LHIsciwxKTt0aGlzLnNpemU9bmV3IEFycmF5KHQpLHRoaXMuc2l6ZS5maWxsKDApLHRoaXMubWV0YWRhdGE9bmV3IE1hcCx0aGlzLmRhdGE9bnVsbH19LEs9UGU7ZnVuY3Rpb24gaHIoZSxBKXtsZXQgdD1udWxsO3N3aXRjaChlKXtjYXNlIFEuVUludDg6e3Q9bmV3IFVpbnQ4QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDg6e3Q9bmV3IEludDhBcnJheShBKTticmVha31jYXNlIFEuVUludDE2Ont0PW5ldyBVaW50MTZBcnJheShBKTticmVha31jYXNlIFEuSW50MTY6e3Q9bmV3IEludDE2QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLlVJbnQzMjp7dD1uZXcgVWludDMyQXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDMyOnt0PW5ldyBJbnQzMkFycmF5KEEpO2JyZWFrfWNhc2UgUS5VSW50NjQ6e3R5cGVvZiBnbG9iYWxUaGlzLkJpZ1VpbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ1VpbnQ2NEFycmF5KEEpOnQ9bmV3IFVpbnQ4QXJyYXkoQSk7YnJlYWt9Y2FzZSBRLkludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdJbnQ2NEFycmF5PT0iZnVuY3Rpb24iP3Q9bmV3IEJpZ0ludDY0QXJyYXkoQSk6dD1uZXcgVWludDhBcnJheShBKTticmVha31jYXNlIFMuRmxvYXQzMjp7dD1uZXcgRmxvYXQzMkFycmF5KEEpO2JyZWFrfWNhc2UgUy5GbG9hdDY0Ont0PW5ldyBGbG9hdDY0QXJyYXkoQSk7YnJlYWt9Y2FzZSJudWxsIjp7dD1udWxsO2JyZWFrfWNhc2UgbnVsbDp7dD1udWxsO2JyZWFrfWRlZmF1bHQ6dGhyb3cgbmV3IEVycm9yKCJUeXBlIGlzIG5vdCBzdXBwb3J0ZWQgYXMgYSBUeXBlZEFycmF5Iil9cmV0dXJuIHR9dmFyIEQ9aHI7ZnVuY3Rpb24gd3IoZSl7bGV0IEE9bmV3IEsoZS5pbWFnZVR5cGUpO2lmKEEubmFtZT1lLm5hbWUsQS5vcmlnaW49QXJyYXkuZnJvbShlLm9yaWdpbiksQS5zcGFjaW5nPUFycmF5LmZyb20oZS5zcGFjaW5nKSxBLmRpcmVjdGlvbj1lLmRpcmVjdGlvbi5zbGljZSgpLEEuc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSksZS5kYXRhIT09bnVsbCl7bGV0IHQ9ZS5kYXRhLmNvbnN0cnVjdG9yO0EuZGF0YT1uZXcgdChlLmRhdGEubGVuZ3RoKSxBLmRhdGEhPW51bGwmJkEuZGF0YS5zZXQoZS5kYXRhLDApfXJldHVybiBBfXZhciB4ZT13cjtmdW5jdGlvbiBScihlKXtpZihlLmxlbmd0aDwxKXRocm93IEVycm9yKCJBdCBsZWFzdCBvbmUgaW1hZ2VzIGlzIHJlcXVpcmVkLiIpO2xldCBBPWVbMF07aWYoQS5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiSW1hZ2UgZGF0YSBpcyBudWxsLiIpO2xldCB0PW5ldyBLKEEuaW1hZ2VUeXBlKTt0Lm9yaWdpbj1BcnJheS5mcm9tKEEub3JpZ2luKSx0LnNwYWNpbmc9QXJyYXkuZnJvbShBLnNwYWNpbmcpO2xldCByPXQuaW1hZ2VUeXBlLmRpbWVuc2lvbjt0LmRpcmVjdGlvbj1BLmRpcmVjdGlvbi5zbGljZSgpO2xldCBhPXItMTt0LnNpemU9QXJyYXkuZnJvbShBLnNpemUpO2xldCBvPWUucmVkdWNlKChuLHUpPT5uK3Uuc2l6ZVthXSwwKTt0LnNpemVbYV09bztsZXQgaT10LnNpemUucmVkdWNlKChuLHUpPT5uKnUsMSkqdC5pbWFnZVR5cGUuY29tcG9uZW50cyxsPUEuZGF0YS5jb25zdHJ1Y3Rvcjt0LmRhdGE9bmV3IGwoaSk7bGV0IGY9dC5pbWFnZVR5cGUuY29tcG9uZW50cztmb3IobGV0IG49MDtuPHQuc2l6ZS5sZW5ndGgtMTtuKyspZio9dC5zaXplW25dO2xldCBnPTA7aWYodC5kYXRhIT1udWxsKWZvcihsZXQgbj0wO248ZS5sZW5ndGg7bisrKXQuZGF0YS5zZXQoZVtuXS5kYXRhLGYqZyksZys9ZVtuXS5zaXplW2FdO2Vsc2UgdGhyb3cgRXJyb3IoIkNvdWxkIG5vdCBjcmVhdGUgcmVzdWx0IGltYWdlIGRhdGEuIik7cmV0dXJuIHR9dmFyIEdlPVJyO2Z1bmN0aW9uIGJyKGUsQSl7bGV0IHQ9T2JqZWN0LmFzc2lnbih7fSxlLmltYWdlVHlwZSk7aWYodHlwZW9mIEE8InUiJiZ0eXBlb2YgQS5waXhlbFR5cGU8InUiJiYodC5waXhlbFR5cGU9QS5waXhlbFR5cGUsQS5waXhlbFR5cGU9PT11ZS5TY2FsYXImJnQuY29tcG9uZW50cyE9PTEpKXRocm93IG5ldyBFcnJvcigiQ2Fubm90IGNhc3QgbXVsdGktY29tcG9uZW50IGltYWdlIHRvIGEgc2NhbGFyIGltYWdlIik7dHlwZW9mIEE8InUiJiZ0eXBlb2YgQS5jb21wb25lbnRUeXBlPCJ1IiYmQS5jb21wb25lbnRUeXBlIT09ZS5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSYmKHQuY29tcG9uZW50VHlwZT1BLmNvbXBvbmVudFR5cGUpO2xldCByPW5ldyBLKHQpO2lmKHIubmFtZT1lLm5hbWUsci5vcmlnaW49QXJyYXkuZnJvbShlLm9yaWdpbiksci5zcGFjaW5nPUFycmF5LmZyb20oZS5zcGFjaW5nKSxyLmRpcmVjdGlvbj1lLmRpcmVjdGlvbi5zbGljZSgpLHIuc2l6ZT1BcnJheS5mcm9tKGUuc2l6ZSksci5tZXRhZGF0YT1uZXcgTWFwKEpTT04ucGFyc2UoSlNPTi5zdHJpbmdpZnkoQXJyYXkuZnJvbShlLm1ldGFkYXRhKSkpKSxlLmRhdGEhPT1udWxsKWlmKHR5cGVvZiBBPCJ1IiYmdHlwZW9mIEEuY29tcG9uZW50VHlwZTwidSImJkEuY29tcG9uZW50VHlwZSE9PWUuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpc3dpdGNoKGUuaW1hZ2VUeXBlLmNvbXBvbmVudFR5cGUpe2Nhc2UgUS5VSW50ODpjYXNlIFEuSW50ODpjYXNlIFEuVUludDE2OmNhc2UgUS5JbnQxNjpjYXNlIFEuVUludDMyOmNhc2UgUS5JbnQzMjpjYXNlIFMuRmxvYXQzMjpjYXNlIFMuRmxvYXQ2NDpzd2l0Y2goci5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSl7Y2FzZSBRLlVJbnQ4OnIuZGF0YT1uZXcgVWludDhBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQ4OnIuZGF0YT1uZXcgSW50OEFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQxNjpyLmRhdGE9bmV3IFVpbnQxNkFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLkludDE2OnIuZGF0YT1uZXcgSW50MTZBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5VSW50MzI6ci5kYXRhPW5ldyBVaW50MzJBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQzMjpyLmRhdGE9bmV3IEludDMyQXJyYXkoZS5kYXRhKTticmVhaztjYXNlIFMuRmxvYXQzMjpyLmRhdGE9bmV3IEZsb2F0MzJBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUy5GbG9hdDY0OnIuZGF0YT1uZXcgRmxvYXQ2NEFycmF5KGUuZGF0YSk7YnJlYWs7Y2FzZSBRLlVJbnQ2NDpyLmRhdGE9bmV3IEJpZ1VpbnQ2NEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPUJpZ0ludC5hc0ludE4oNjQsQmlnSW50KGUuZGF0YVthXSkpO2JyZWFrO2Nhc2UgUS5JbnQ2NDpyLmRhdGE9bmV3IEJpZ0ludDY0QXJyYXkoZS5kYXRhLmxlbmd0aCk7Zm9yKGxldCBhPTA7YTxyLmRhdGEubGVuZ3RoO2ErKylyLmRhdGFbYV09QmlnSW50LmFzVWludE4oNjQsQmlnSW50KGUuZGF0YVthXSkpO2JyZWFrfWJyZWFrO2Nhc2UgUS5VSW50NjQ6Y2FzZSBRLkludDY0OnN3aXRjaChyLmltYWdlVHlwZS5jb21wb25lbnRUeXBlKXtjYXNlIFEuVUludDg6ci5kYXRhPW5ldyBVaW50OEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5JbnQ4OnIuZGF0YT1uZXcgSW50OEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50MTY6ci5kYXRhPW5ldyBVaW50MTZBcnJheShlLmRhdGEubGVuZ3RoKTtmb3IobGV0IGE9MDthPHIuZGF0YS5sZW5ndGg7YSsrKXIuZGF0YVthXT1OdW1iZXIoZS5kYXRhW2FdKTticmVhaztjYXNlIFEuSW50MTY6ci5kYXRhPW5ldyBJbnQxNkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50MzI6ci5kYXRhPW5ldyBVaW50MzJBcnJheShlLmRhdGEubGVuZ3RoKTtmb3IobGV0IGE9MDthPHIuZGF0YS5sZW5ndGg7YSsrKXIuZGF0YVthXT1OdW1iZXIoZS5kYXRhW2FdKTticmVhaztjYXNlIFEuSW50MzI6ci5kYXRhPW5ldyBJbnQzMkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUy5GbG9hdDMyOnIuZGF0YT1uZXcgRmxvYXQzMkFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUy5GbG9hdDY0OnIuZGF0YT1uZXcgRmxvYXQ2NEFycmF5KGUuZGF0YS5sZW5ndGgpO2ZvcihsZXQgYT0wO2E8ci5kYXRhLmxlbmd0aDthKyspci5kYXRhW2FdPU51bWJlcihlLmRhdGFbYV0pO2JyZWFrO2Nhc2UgUS5VSW50NjQ6ci5kYXRhPW5ldyBCaWdVaW50NjRBcnJheShlLmRhdGEpO2JyZWFrO2Nhc2UgUS5JbnQ2NDpyLmRhdGE9bmV3IEJpZ0ludDY0QXJyYXkoZS5kYXRhKTticmVha31icmVha31lbHNle2xldCBhPWUuZGF0YS5jb25zdHJ1Y3RvcjtyLmRhdGE9bmV3IGEoZS5kYXRhLmxlbmd0aCksci5kYXRhIT1udWxsJiZyLmRhdGEuc2V0KGUuZGF0YSwwKX1yZXR1cm4gcn12YXIgVD1icjt2YXIga3I9ZnVuY3Rpb24oZSxBKXt2YXIgdD17fTtmb3IodmFyIHIgaW4gZSlPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoZSxyKSYmQS5pbmRleE9mKHIpPDAmJih0W3JdPWVbcl0pO2lmKGUhPW51bGwmJnR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzPT0iZnVuY3Rpb24iKWZvcih2YXIgYT0wLHI9T2JqZWN0LmdldE93blByb3BlcnR5U3ltYm9scyhlKTthPHIubGVuZ3RoO2ErKylBLmluZGV4T2YoclthXSk8MCYmT2JqZWN0LnByb3RvdHlwZS5wcm9wZXJ0eUlzRW51bWVyYWJsZS5jYWxsKGUsclthXSkmJih0W3JbYV1dPWVbclthXV0pO3JldHVybiB0fSxUZT1jbGFzc3tjb25zdHJ1Y3RvcihBLHQpe3RoaXMuZmNuPXQsdGhpcy53b3JrZXJRdWV1ZT1uZXcgQXJyYXkoQSksdGhpcy53b3JrZXJRdWV1ZS5maWxsKG51bGwpLHRoaXMucnVuSW5mbz1bXX1ydW5UYXNrcyhBLHQ9bnVsbCl7bGV0IHI9e3Rhc2tRdWV1ZTpbXSxyZXN1bHRzOltdLGFkZGluZ1Rhc2tzOiExLHBvc3Rwb25lZDohMSxydW5uaW5nV29ya2VyczowLGluZGV4OjAsY29tcGxldGVkVGFza3M6MCxwcm9ncmVzc0NhbGxiYWNrOnQsY2FuY2VsZWQ6ITF9O3JldHVybiB0aGlzLnJ1bkluZm8ucHVzaChyKSxyLmluZGV4PXRoaXMucnVuSW5mby5sZW5ndGgtMSx7cHJvbWlzZTpuZXcgUHJvbWlzZSgoYSxvKT0+e3IucmVzb2x2ZT1hLHIucmVqZWN0PW8sci5yZXN1bHRzPW5ldyBBcnJheShBLmxlbmd0aCksci5jb21wbGV0ZWRUYXNrcz0wLHIuYWRkaW5nVGFza3M9ITAsQS5mb3JFYWNoKChpLGwpPT57dGhpcy5hZGRUYXNrKHIuaW5kZXgsbCxpKX0pLHIuYWRkaW5nVGFza3M9ITF9KSxydW5JZDpyLmluZGV4fX10ZXJtaW5hdGVXb3JrZXJzKCl7Zm9yKGxldCBBPTA7QTx0aGlzLndvcmtlclF1ZXVlLmxlbmd0aDtBKyspe2xldCB0PXRoaXMud29ya2VyUXVldWVbQV07dD8udGVybWluYXRlKCksdGhpcy53b3JrZXJRdWV1ZVtBXT1udWxsfX1jYW5jZWwoQSl7bGV0IHQ9dGhpcy5ydW5JbmZvW0FdO3QhPW51bGwmJih0LmNhbmNlbGVkPSEwKX1hZGRUYXNrKEEsdCxyKXtsZXQgYT10aGlzLnJ1bkluZm9bQV07aWYoYT8uY2FuY2VsZWQ9PT0hMCl7YS5yZWplY3QoIlJlbWFpbmluZyB0YXNrcyBjYW5jZWxlZCIpLHRoaXMuY2xlYXJUYXNrKGEuaW5kZXgpO3JldHVybn1pZih0aGlzLndvcmtlclF1ZXVlLmxlbmd0aD4wKXtsZXQgbz10aGlzLndvcmtlclF1ZXVlLnBvcCgpO2EucnVubmluZ1dvcmtlcnMrKyx0aGlzLmZjbihvLC4uLnIpLnRoZW4oaT0+e3Zhcnt3ZWJXb3JrZXI6bH09aSxmPWtyKGksWyJ3ZWJXb3JrZXIiXSk7aWYodGhpcy53b3JrZXJRdWV1ZS5wdXNoKGwpLHRoaXMucnVuSW5mb1tBXSE9PW51bGwpe2lmKGEucnVubmluZ1dvcmtlcnMtLSxhLnJlc3VsdHNbdF09ZixhLmNvbXBsZXRlZFRhc2tzKyssYS5wcm9ncmVzc0NhbGxiYWNrIT1udWxsJiZhLnByb2dyZXNzQ2FsbGJhY2soYS5jb21wbGV0ZWRUYXNrcyxhLnJlc3VsdHMubGVuZ3RoKSxhLnRhc2tRdWV1ZS5sZW5ndGg+MCl7bGV0IGc9YS50YXNrUXVldWUuc2hpZnQoKTt0aGlzLmFkZFRhc2soQSxnWzBdLGdbMV0pfWVsc2UgaWYoIWEuYWRkaW5nVGFza3MmJmEucnVubmluZ1dvcmtlcnM9PT0wKXtsZXQgZz1hLnJlc3VsdHM7YS5yZXNvbHZlKGcpLHRoaXMuY2xlYXJUYXNrKGEuaW5kZXgpfX19KS5jYXRjaChpPT57YS5yZWplY3QoaSksdGhpcy5jbGVhclRhc2soYS5pbmRleCl9KX1lbHNlIGEucnVubmluZ1dvcmtlcnMhPT0wfHxhLnBvc3Rwb25lZD9hLnRhc2tRdWV1ZS5wdXNoKFt0LHJdKTooYS5wb3N0cG9uZWQ9ITAsc2V0VGltZW91dCgoKT0+e2EucG9zdHBvbmVkPSExLHRoaXMuYWRkVGFzayhhLmluZGV4LHQscil9LDUwKSl9Y2xlYXJUYXNrKEEpe3RoaXMucnVuSW5mb1tBXS5yZXN1bHRzPVtdLHRoaXMucnVuSW5mb1tBXS50YXNrUXVldWU9W10sdGhpcy5ydW5JbmZvW0FdLnByb2dyZXNzQ2FsbGJhY2s9bnVsbCx0aGlzLnJ1bkluZm9bQV0uY2FuY2VsZWQ9bnVsbCx0aGlzLnJ1bkluZm9bQV0ucmVqZWN0PSgpPT57fSx0aGlzLnJ1bkluZm9bQV0ucmVzb2x2ZT0oKT0+e319fSxKZT1UZTt2YXIgRHI9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIEZyKGUpe2lmKGU9PW51bGwpcmV0dXJuW107bGV0IEE9W107Zm9yKGxldCB0PTA7dDxlLmxlbmd0aDt0Kyspe2xldCByPU9yKGVbdF0pO3IhPT1udWxsJiZBLnB1c2gocil9cmV0dXJuIEF9ZnVuY3Rpb24gT3IoZSl7aWYoZT09bnVsbClyZXR1cm4gbnVsbDtsZXQgQT1udWxsO3JldHVybiBlLmJ1ZmZlciE9PXZvaWQgMD9BPWUuYnVmZmVyOmUuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKEE9ZSksRHImJkEgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOkF9dmFyIGx0PUZyO2Z1bmN0aW9uIGllKGUsQSl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuIGUuYXBwbHkoQSxhcmd1bWVudHMpfX12YXJ7dG9TdHJpbmc6VXJ9PU9iamVjdC5wcm90b3R5cGUse2dldFByb3RvdHlwZU9mOkhlfT1PYmplY3QsY2U9KGU9PkE9PntsZXQgdD1Vci5jYWxsKEEpO3JldHVybiBlW3RdfHwoZVt0XT10LnNsaWNlKDgsLTEpLnRvTG93ZXJDYXNlKCkpfSkoT2JqZWN0LmNyZWF0ZShudWxsKSkseD1lPT4oZT1lLnRvTG93ZXJDYXNlKCksQT0+Y2UoQSk9PT1lKSxkZT1lPT5BPT50eXBlb2YgQT09PWUse2lzQXJyYXk6an09QXJyYXksYWU9ZGUoInVuZGVmaW5lZCIpO2Z1bmN0aW9uIFNyKGUpe3JldHVybiBlIT09bnVsbCYmIWFlKGUpJiZlLmNvbnN0cnVjdG9yIT09bnVsbCYmIWFlKGUuY29uc3RydWN0b3IpJiZQKGUuY29uc3RydWN0b3IuaXNCdWZmZXIpJiZlLmNvbnN0cnVjdG9yLmlzQnVmZmVyKGUpfXZhciBtdD14KCJBcnJheUJ1ZmZlciIpO2Z1bmN0aW9uIFdyKGUpe2xldCBBO3JldHVybiB0eXBlb2YgQXJyYXlCdWZmZXI8InUiJiZBcnJheUJ1ZmZlci5pc1ZpZXc/QT1BcnJheUJ1ZmZlci5pc1ZpZXcoZSk6QT1lJiZlLmJ1ZmZlciYmbXQoZS5idWZmZXIpLEF9dmFyIE5yPWRlKCJzdHJpbmciKSxQPWRlKCJmdW5jdGlvbiIpLHV0PWRlKCJudW1iZXIiKSxCZT1lPT5lIT09bnVsbCYmdHlwZW9mIGU9PSJvYmplY3QiLFByPWU9PmU9PT0hMHx8ZT09PSExLGZlPWU9PntpZihjZShlKSE9PSJvYmplY3QiKXJldHVybiExO2xldCBBPUhlKGUpO3JldHVybihBPT09bnVsbHx8QT09PU9iamVjdC5wcm90b3R5cGV8fE9iamVjdC5nZXRQcm90b3R5cGVPZihBKT09PW51bGwpJiYhKFN5bWJvbC50b1N0cmluZ1RhZyBpbiBlKSYmIShTeW1ib2wuaXRlcmF0b3IgaW4gZSl9LHhyPXgoIkRhdGUiKSxHcj14KCJGaWxlIiksVHI9eCgiQmxvYiIpLEpyPXgoIkZpbGVMaXN0IiksTHI9ZT0+QmUoZSkmJlAoZS5waXBlKSxNcj1lPT57bGV0IEE7cmV0dXJuIGUmJih0eXBlb2YgRm9ybURhdGE9PSJmdW5jdGlvbiImJmUgaW5zdGFuY2VvZiBGb3JtRGF0YXx8UChlLmFwcGVuZCkmJigoQT1jZShlKSk9PT0iZm9ybWRhdGEifHxBPT09Im9iamVjdCImJlAoZS50b1N0cmluZykmJmUudG9TdHJpbmcoKT09PSJbb2JqZWN0IEZvcm1EYXRhXSIpKX0sSHI9eCgiVVJMU2VhcmNoUGFyYW1zIiksWXI9ZT0+ZS50cmltP2UudHJpbSgpOmUucmVwbGFjZSgvXltcc1x1RkVGRlx4QTBdK3xbXHNcdUZFRkZceEEwXSskL2csIiIpO2Z1bmN0aW9uIG9lKGUsQSx7YWxsT3duS2V5czp0PSExfT17fSl7aWYoZT09PW51bGx8fHR5cGVvZiBlPiJ1IilyZXR1cm47bGV0IHIsYTtpZih0eXBlb2YgZSE9Im9iamVjdCImJihlPVtlXSksaihlKSlmb3Iocj0wLGE9ZS5sZW5ndGg7cjxhO3IrKylBLmNhbGwobnVsbCxlW3JdLHIsZSk7ZWxzZXtsZXQgbz10P09iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKGUpOk9iamVjdC5rZXlzKGUpLGk9by5sZW5ndGgsbDtmb3Iocj0wO3I8aTtyKyspbD1vW3JdLEEuY2FsbChudWxsLGVbbF0sbCxlKX19ZnVuY3Rpb24gZnQoZSxBKXtBPUEudG9Mb3dlckNhc2UoKTtsZXQgdD1PYmplY3Qua2V5cyhlKSxyPXQubGVuZ3RoLGE7Zm9yKDtyLS0gPjA7KWlmKGE9dFtyXSxBPT09YS50b0xvd2VyQ2FzZSgpKXJldHVybiBhO3JldHVybiBudWxsfXZhciBjdD0oKCk9PnR5cGVvZiBnbG9iYWxUaGlzPCJ1Ij9nbG9iYWxUaGlzOnR5cGVvZiBzZWxmPCJ1Ij9zZWxmOnR5cGVvZiB3aW5kb3c8InUiP3dpbmRvdzpnbG9iYWwpKCksZHQ9ZT0+IWFlKGUpJiZlIT09Y3Q7ZnVuY3Rpb24gTWUoKXtsZXR7Y2FzZWxlc3M6ZX09ZHQodGhpcykmJnRoaXN8fHt9LEE9e30sdD0ocixhKT0+e2xldCBvPWUmJmZ0KEEsYSl8fGE7ZmUoQVtvXSkmJmZlKHIpP0Fbb109TWUoQVtvXSxyKTpmZShyKT9BW29dPU1lKHt9LHIpOmoocik/QVtvXT1yLnNsaWNlKCk6QVtvXT1yfTtmb3IobGV0IHI9MCxhPWFyZ3VtZW50cy5sZW5ndGg7cjxhO3IrKylhcmd1bWVudHNbcl0mJm9lKGFyZ3VtZW50c1tyXSx0KTtyZXR1cm4gQX12YXIgcXI9KGUsQSx0LHthbGxPd25LZXlzOnJ9PXt9KT0+KG9lKEEsKGEsbyk9Pnt0JiZQKGEpP2Vbb109aWUoYSx0KTplW29dPWF9LHthbGxPd25LZXlzOnJ9KSxlKSx2cj1lPT4oZS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihlPWUuc2xpY2UoMSkpLGUpLEtyPShlLEEsdCxyKT0+e2UucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoQS5wcm90b3R5cGUsciksZS5wcm90b3R5cGUuY29uc3RydWN0b3I9ZSxPYmplY3QuZGVmaW5lUHJvcGVydHkoZSwic3VwZXIiLHt2YWx1ZTpBLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oZS5wcm90b3R5cGUsdCl9LGpyPShlLEEsdCxyKT0+e2xldCBhLG8saSxsPXt9O2lmKEE9QXx8e30sZT09bnVsbClyZXR1cm4gQTtkb3tmb3IoYT1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhlKSxvPWEubGVuZ3RoO28tLSA+MDspaT1hW29dLCghcnx8cihpLGUsQSkpJiYhbFtpXSYmKEFbaV09ZVtpXSxsW2ldPSEwKTtlPXQhPT0hMSYmSGUoZSl9d2hpbGUoZSYmKCF0fHx0KGUsQSkpJiZlIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIEF9LF9yPShlLEEsdCk9PntlPVN0cmluZyhlKSwodD09PXZvaWQgMHx8dD5lLmxlbmd0aCkmJih0PWUubGVuZ3RoKSx0LT1BLmxlbmd0aDtsZXQgcj1lLmluZGV4T2YoQSx0KTtyZXR1cm4gciE9PS0xJiZyPT09dH0senI9ZT0+e2lmKCFlKXJldHVybiBudWxsO2lmKGooZSkpcmV0dXJuIGU7bGV0IEE9ZS5sZW5ndGg7aWYoIXV0KEEpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShBKTtmb3IoO0EtLSA+MDspdFtBXT1lW0FdO3JldHVybiB0fSxWcj0oZT0+QT0+ZSYmQSBpbnN0YW5jZW9mIGUpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmSGUoVWludDhBcnJheSkpLFpyPShlLEEpPT57bGV0IHI9KGUmJmVbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChlKSxhO2Zvcig7KGE9ci5uZXh0KCkpJiYhYS5kb25lOyl7bGV0IG89YS52YWx1ZTtBLmNhbGwoZSxvWzBdLG9bMV0pfX0sWHI9KGUsQSk9PntsZXQgdCxyPVtdO2Zvcig7KHQ9ZS5leGVjKEEpKSE9PW51bGw7KXIucHVzaCh0KTtyZXR1cm4gcn0sJHI9eCgiSFRNTEZvcm1FbGVtZW50IiksZWk9ZT0+ZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xzXShbYS16XGRdKShcdyopL2csZnVuY3Rpb24odCxyLGEpe3JldHVybiByLnRvVXBwZXJDYXNlKCkrYX0pLGd0PSgoe2hhc093blByb3BlcnR5OmV9KT0+KEEsdCk9PmUuY2FsbChBLHQpKShPYmplY3QucHJvdG90eXBlKSxBaT14KCJSZWdFeHAiKSxCdD0oZSxBKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKGUpLHI9e307b2UodCwoYSxvKT0+e2xldCBpOyhpPUEoYSxvLGUpKSE9PSExJiYocltvXT1pfHxhKX0pLE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKGUscil9LHRpPWU9PntCdChlLChBLHQpPT57aWYoUChlKSYmWyJhcmd1bWVudHMiLCJjYWxsZXIiLCJjYWxsZWUiXS5pbmRleE9mKHQpIT09LTEpcmV0dXJuITE7bGV0IHI9ZVt0XTtpZihQKHIpKXtpZihBLmVudW1lcmFibGU9ITEsIndyaXRhYmxlImluIEEpe0Eud3JpdGFibGU9ITE7cmV0dXJufUEuc2V0fHwoQS5zZXQ9KCk9Pnt0aHJvdyBFcnJvcigiQ2FuIG5vdCByZXdyaXRlIHJlYWQtb25seSBtZXRob2QgJyIrdCsiJyIpfSl9fSl9LHJpPShlLEEpPT57bGV0IHQ9e30scj1hPT57YS5mb3JFYWNoKG89Pnt0W29dPSEwfSl9O3JldHVybiBqKGUpP3IoZSk6cihTdHJpbmcoZSkuc3BsaXQoQSkpLHR9LGlpPSgpPT57fSxhaT0oZSxBKT0+KGU9K2UsTnVtYmVyLmlzRmluaXRlKGUpP2U6QSksTGU9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6IixwdD0iMDEyMzQ1Njc4OSIsQ3Q9e0RJR0lUOnB0LEFMUEhBOkxlLEFMUEhBX0RJR0lUOkxlK0xlLnRvVXBwZXJDYXNlKCkrcHR9LG9pPShlPTE2LEE9Q3QuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpyfT1BO2Zvcig7ZS0tOyl0Kz1BW01hdGgucmFuZG9tKCkqcnwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gbmkoZSl7cmV0dXJuISEoZSYmUChlLmFwcGVuZCkmJmVbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJmVbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIHNpPWU9PntsZXQgQT1uZXcgQXJyYXkoMTApLHQ9KHIsYSk9PntpZihCZShyKSl7aWYoQS5pbmRleE9mKHIpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gcikpe0FbYV09cjtsZXQgbz1qKHIpP1tdOnt9O3JldHVybiBvZShyLChpLGwpPT57bGV0IGY9dChpLGErMSk7IWFlKGYpJiYob1tsXT1mKX0pLEFbYV09dm9pZCAwLG99fXJldHVybiByfTtyZXR1cm4gdChlLDApfSxJaT14KCJBc3luY0Z1bmN0aW9uIiksbGk9ZT0+ZSYmKEJlKGUpfHxQKGUpKSYmUChlLnRoZW4pJiZQKGUuY2F0Y2gpLGM9e2lzQXJyYXk6aixpc0FycmF5QnVmZmVyOm10LGlzQnVmZmVyOlNyLGlzRm9ybURhdGE6TXIsaXNBcnJheUJ1ZmZlclZpZXc6V3IsaXNTdHJpbmc6TnIsaXNOdW1iZXI6dXQsaXNCb29sZWFuOlByLGlzT2JqZWN0OkJlLGlzUGxhaW5PYmplY3Q6ZmUsaXNVbmRlZmluZWQ6YWUsaXNEYXRlOnhyLGlzRmlsZTpHcixpc0Jsb2I6VHIsaXNSZWdFeHA6QWksaXNGdW5jdGlvbjpQLGlzU3RyZWFtOkxyLGlzVVJMU2VhcmNoUGFyYW1zOkhyLGlzVHlwZWRBcnJheTpWcixpc0ZpbGVMaXN0OkpyLGZvckVhY2g6b2UsbWVyZ2U6TWUsZXh0ZW5kOnFyLHRyaW06WXIsc3RyaXBCT006dnIsaW5oZXJpdHM6S3IsdG9GbGF0T2JqZWN0OmpyLGtpbmRPZjpjZSxraW5kT2ZUZXN0OngsZW5kc1dpdGg6X3IsdG9BcnJheTp6cixmb3JFYWNoRW50cnk6WnIsbWF0Y2hBbGw6WHIsaXNIVE1MRm9ybTokcixoYXNPd25Qcm9wZXJ0eTpndCxoYXNPd25Qcm9wOmd0LHJlZHVjZURlc2NyaXB0b3JzOkJ0LGZyZWV6ZU1ldGhvZHM6dGksdG9PYmplY3RTZXQ6cmksdG9DYW1lbENhc2U6ZWksbm9vcDppaSx0b0Zpbml0ZU51bWJlcjphaSxmaW5kS2V5OmZ0LGdsb2JhbDpjdCxpc0NvbnRleHREZWZpbmVkOmR0LEFMUEhBQkVUOkN0LGdlbmVyYXRlU3RyaW5nOm9pLGlzU3BlY0NvbXBsaWFudEZvcm06bmksdG9KU09OT2JqZWN0OnNpLGlzQXN5bmNGbjpJaSxpc1RoZW5hYmxlOmxpfTtmdW5jdGlvbiBfKGUsQSx0LHIsYSl7RXJyb3IuY2FsbCh0aGlzKSxFcnJvci5jYXB0dXJlU3RhY2tUcmFjZT9FcnJvci5jYXB0dXJlU3RhY2tUcmFjZSh0aGlzLHRoaXMuY29uc3RydWN0b3IpOnRoaXMuc3RhY2s9bmV3IEVycm9yKCkuc3RhY2ssdGhpcy5tZXNzYWdlPWUsdGhpcy5uYW1lPSJBeGlvc0Vycm9yIixBJiYodGhpcy5jb2RlPUEpLHQmJih0aGlzLmNvbmZpZz10KSxyJiYodGhpcy5yZXF1ZXN0PXIpLGEmJih0aGlzLnJlc3BvbnNlPWEpfWMuaW5oZXJpdHMoXyxFcnJvcix7dG9KU09OOmZ1bmN0aW9uKCl7cmV0dXJue21lc3NhZ2U6dGhpcy5tZXNzYWdlLG5hbWU6dGhpcy5uYW1lLGRlc2NyaXB0aW9uOnRoaXMuZGVzY3JpcHRpb24sbnVtYmVyOnRoaXMubnVtYmVyLGZpbGVOYW1lOnRoaXMuZmlsZU5hbWUsbGluZU51bWJlcjp0aGlzLmxpbmVOdW1iZXIsY29sdW1uTnVtYmVyOnRoaXMuY29sdW1uTnVtYmVyLHN0YWNrOnRoaXMuc3RhY2ssY29uZmlnOmMudG9KU09OT2JqZWN0KHRoaXMuY29uZmlnKSxjb2RlOnRoaXMuY29kZSxzdGF0dXM6dGhpcy5yZXNwb25zZSYmdGhpcy5yZXNwb25zZS5zdGF0dXM/dGhpcy5yZXNwb25zZS5zdGF0dXM6bnVsbH19fSk7dmFyIHl0PV8ucHJvdG90eXBlLEV0PXt9O1siRVJSX0JBRF9PUFRJT05fVkFMVUUiLCJFUlJfQkFEX09QVElPTiIsIkVDT05OQUJPUlRFRCIsIkVUSU1FRE9VVCIsIkVSUl9ORVRXT1JLIiwiRVJSX0ZSX1RPT19NQU5ZX1JFRElSRUNUUyIsIkVSUl9ERVBSRUNBVEVEIiwiRVJSX0JBRF9SRVNQT05TRSIsIkVSUl9CQURfUkVRVUVTVCIsIkVSUl9DQU5DRUxFRCIsIkVSUl9OT1RfU1VQUE9SVCIsIkVSUl9JTlZBTElEX1VSTCJdLmZvckVhY2goZT0+e0V0W2VdPXt2YWx1ZTplfX0pO09iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKF8sRXQpO09iamVjdC5kZWZpbmVQcm9wZXJ0eSh5dCwiaXNBeGlvc0Vycm9yIix7dmFsdWU6ITB9KTtfLmZyb209KGUsQSx0LHIsYSxvKT0+e2xldCBpPU9iamVjdC5jcmVhdGUoeXQpO3JldHVybiBjLnRvRmxhdE9iamVjdChlLGksZnVuY3Rpb24oZil7cmV0dXJuIGYhPT1FcnJvci5wcm90b3R5cGV9LGw9PmwhPT0iaXNBeGlvc0Vycm9yIiksXy5jYWxsKGksZS5tZXNzYWdlLEEsdCxyLGEpLGkuY2F1c2U9ZSxpLm5hbWU9ZS5uYW1lLG8mJk9iamVjdC5hc3NpZ24oaSxvKSxpfTt2YXIgaD1fO3ZhciBDZT1udWxsO2Z1bmN0aW9uIFllKGUpe3JldHVybiBjLmlzUGxhaW5PYmplY3QoZSl8fGMuaXNBcnJheShlKX1mdW5jdGlvbiBodChlKXtyZXR1cm4gYy5lbmRzV2l0aChlLCJbXSIpP2Uuc2xpY2UoMCwtMik6ZX1mdW5jdGlvbiBRdChlLEEsdCl7cmV0dXJuIGU/ZS5jb25jYXQoQSkubWFwKGZ1bmN0aW9uKGEsbyl7cmV0dXJuIGE9aHQoYSksIXQmJm8/IlsiK2ErIl0iOmF9KS5qb2luKHQ/Ii4iOiIiKTpBfWZ1bmN0aW9uIGdpKGUpe3JldHVybiBjLmlzQXJyYXkoZSkmJiFlLnNvbWUoWWUpfXZhciBwaT1jLnRvRmxhdE9iamVjdChjLHt9LG51bGwsZnVuY3Rpb24oQSl7cmV0dXJuL15pc1tBLVpdLy50ZXN0KEEpfSk7ZnVuY3Rpb24gbWkoZSxBLHQpe2lmKCFjLmlzT2JqZWN0KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoInRhcmdldCBtdXN0IGJlIGFuIG9iamVjdCIpO0E9QXx8bmV3KENlfHxGb3JtRGF0YSksdD1jLnRvRmxhdE9iamVjdCh0LHttZXRhVG9rZW5zOiEwLGRvdHM6ITEsaW5kZXhlczohMX0sITEsZnVuY3Rpb24oZCxFKXtyZXR1cm4hYy5pc1VuZGVmaW5lZChFW2RdKX0pO2xldCByPXQubWV0YVRva2VucyxhPXQudmlzaXRvcnx8bixvPXQuZG90cyxpPXQuaW5kZXhlcyxmPSh0LkJsb2J8fHR5cGVvZiBCbG9iPCJ1IiYmQmxvYikmJmMuaXNTcGVjQ29tcGxpYW50Rm9ybShBKTtpZighYy5pc0Z1bmN0aW9uKGEpKXRocm93IG5ldyBUeXBlRXJyb3IoInZpc2l0b3IgbXVzdCBiZSBhIGZ1bmN0aW9uIik7ZnVuY3Rpb24gZyhJKXtpZihJPT09bnVsbClyZXR1cm4iIjtpZihjLmlzRGF0ZShJKSlyZXR1cm4gSS50b0lTT1N0cmluZygpO2lmKCFmJiZjLmlzQmxvYihJKSl0aHJvdyBuZXcgaCgiQmxvYiBpcyBub3Qgc3VwcG9ydGVkLiBVc2UgYSBCdWZmZXIgaW5zdGVhZC4iKTtyZXR1cm4gYy5pc0FycmF5QnVmZmVyKEkpfHxjLmlzVHlwZWRBcnJheShJKT9mJiZ0eXBlb2YgQmxvYj09ImZ1bmN0aW9uIj9uZXcgQmxvYihbSV0pOkJ1ZmZlci5mcm9tKEkpOkl9ZnVuY3Rpb24gbihJLGQsRSl7bGV0IFI9STtpZihJJiYhRSYmdHlwZW9mIEk9PSJvYmplY3QiKXtpZihjLmVuZHNXaXRoKGQsInt9IikpZD1yP2Q6ZC5zbGljZSgwLC0yKSxJPUpTT04uc3RyaW5naWZ5KEkpO2Vsc2UgaWYoYy5pc0FycmF5KEkpJiZnaShJKXx8KGMuaXNGaWxlTGlzdChJKXx8Yy5lbmRzV2l0aChkLCJbXSIpKSYmKFI9Yy50b0FycmF5KEkpKSlyZXR1cm4gZD1odChkKSxSLmZvckVhY2goZnVuY3Rpb24oayxXZSl7IShjLmlzVW5kZWZpbmVkKGspfHxrPT09bnVsbCkmJkEuYXBwZW5kKGk9PT0hMD9RdChbZF0sV2Usbyk6aT09PW51bGw/ZDpkKyJbXSIsZyhrKSl9KSwhMX1yZXR1cm4gWWUoSSk/ITA6KEEuYXBwZW5kKFF0KEUsZCxvKSxnKEkpKSwhMSl9bGV0IHU9W10scD1PYmplY3QuYXNzaWduKHBpLHtkZWZhdWx0VmlzaXRvcjpuLGNvbnZlcnRWYWx1ZTpnLGlzVmlzaXRhYmxlOlllfSk7ZnVuY3Rpb24gcyhJLGQpe2lmKCFjLmlzVW5kZWZpbmVkKEkpKXtpZih1LmluZGV4T2YoSSkhPT0tMSl0aHJvdyBFcnJvcigiQ2lyY3VsYXIgcmVmZXJlbmNlIGRldGVjdGVkIGluICIrZC5qb2luKCIuIikpO3UucHVzaChJKSxjLmZvckVhY2goSSxmdW5jdGlvbihSLHcpeyghKGMuaXNVbmRlZmluZWQoUil8fFI9PT1udWxsKSYmYS5jYWxsKEEsUixjLmlzU3RyaW5nKHcpP3cudHJpbSgpOncsZCxwKSk9PT0hMCYmcyhSLGQ/ZC5jb25jYXQodyk6W3ddKX0pLHUucG9wKCl9fWlmKCFjLmlzT2JqZWN0KGUpKXRocm93IG5ldyBUeXBlRXJyb3IoImRhdGEgbXVzdCBiZSBhbiBvYmplY3QiKTtyZXR1cm4gcyhlKSxBfXZhciBKPW1pO2Z1bmN0aW9uIHd0KGUpe2xldCBBPXsiISI6IiUyMSIsIiciOiIlMjciLCIoIjoiJTI4IiwiKSI6IiUyOSIsIn4iOiIlN0UiLCIlMjAiOiIrIiwiJTAwIjoiXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KGUpLnJlcGxhY2UoL1shJygpfl18JTIwfCUwMC9nLGZ1bmN0aW9uKHIpe3JldHVybiBBW3JdfSl9ZnVuY3Rpb24gUnQoZSxBKXt0aGlzLl9wYWlycz1bXSxlJiZKKGUsdGhpcyxBKX12YXIgYnQ9UnQucHJvdG90eXBlO2J0LmFwcGVuZD1mdW5jdGlvbihBLHQpe3RoaXMuX3BhaXJzLnB1c2goW0EsdF0pfTtidC50b1N0cmluZz1mdW5jdGlvbihBKXtsZXQgdD1BP2Z1bmN0aW9uKHIpe3JldHVybiBBLmNhbGwodGhpcyxyLHd0KX06d3Q7cmV0dXJuIHRoaXMuX3BhaXJzLm1hcChmdW5jdGlvbihhKXtyZXR1cm4gdChhWzBdKSsiPSIrdChhWzFdKX0sIiIpLmpvaW4oIiYiKX07dmFyIHllPVJ0O2Z1bmN0aW9uIHVpKGUpe3JldHVybiBlbmNvZGVVUklDb21wb25lbnQoZSkucmVwbGFjZSgvJTNBL2dpLCI6IikucmVwbGFjZSgvJTI0L2csIiQiKS5yZXBsYWNlKC8lMkMvZ2ksIiwiKS5yZXBsYWNlKC8lMjAvZywiKyIpLnJlcGxhY2UoLyU1Qi9naSwiWyIpLnJlcGxhY2UoLyU1RC9naSwiXSIpfWZ1bmN0aW9uIG5lKGUsQSx0KXtpZighQSlyZXR1cm4gZTtsZXQgcj10JiZ0LmVuY29kZXx8dWksYT10JiZ0LnNlcmlhbGl6ZSxvO2lmKGE/bz1hKEEsdCk6bz1jLmlzVVJMU2VhcmNoUGFyYW1zKEEpP0EudG9TdHJpbmcoKTpuZXcgeWUoQSx0KS50b1N0cmluZyhyKSxvKXtsZXQgaT1lLmluZGV4T2YoIiMiKTtpIT09LTEmJihlPWUuc2xpY2UoMCxpKSksZSs9KGUuaW5kZXhPZigiPyIpPT09LTE/Ij8iOiImIikrb31yZXR1cm4gZX12YXIgcWU9Y2xhc3N7Y29uc3RydWN0b3IoKXt0aGlzLmhhbmRsZXJzPVtdfXVzZShBLHQscil7cmV0dXJuIHRoaXMuaGFuZGxlcnMucHVzaCh7ZnVsZmlsbGVkOkEscmVqZWN0ZWQ6dCxzeW5jaHJvbm91czpyP3Iuc3luY2hyb25vdXM6ITEscnVuV2hlbjpyP3IucnVuV2hlbjpudWxsfSksdGhpcy5oYW5kbGVycy5sZW5ndGgtMX1lamVjdChBKXt0aGlzLmhhbmRsZXJzW0FdJiYodGhpcy5oYW5kbGVyc1tBXT1udWxsKX1jbGVhcigpe3RoaXMuaGFuZGxlcnMmJih0aGlzLmhhbmRsZXJzPVtdKX1mb3JFYWNoKEEpe2MuZm9yRWFjaCh0aGlzLmhhbmRsZXJzLGZ1bmN0aW9uKHIpe3IhPT1udWxsJiZBKHIpfSl9fSx2ZT1xZTt2YXIgRWU9e3NpbGVudEpTT05QYXJzaW5nOiEwLGZvcmNlZEpTT05QYXJzaW5nOiEwLGNsYXJpZnlUaW1lb3V0RXJyb3I6ITF9O3ZhciBrdD10eXBlb2YgVVJMU2VhcmNoUGFyYW1zPCJ1Ij9VUkxTZWFyY2hQYXJhbXM6eWU7dmFyIER0PXR5cGVvZiBGb3JtRGF0YTwidSI/Rm9ybURhdGE6bnVsbDt2YXIgRnQ9dHlwZW9mIEJsb2I8InUiP0Jsb2I6bnVsbDt2YXIgZmk9KCgpPT57bGV0IGU7cmV0dXJuIHR5cGVvZiBuYXZpZ2F0b3I8InUiJiYoKGU9bmF2aWdhdG9yLnByb2R1Y3QpPT09IlJlYWN0TmF0aXZlInx8ZT09PSJOYXRpdmVTY3JpcHQifHxlPT09Ik5TIik/ITE6dHlwZW9mIHdpbmRvdzwidSImJnR5cGVvZiBkb2N1bWVudDwidSJ9KSgpLGNpPSgoKT0+dHlwZW9mIFdvcmtlckdsb2JhbFNjb3BlPCJ1IiYmc2VsZiBpbnN0YW5jZW9mIFdvcmtlckdsb2JhbFNjb3BlJiZ0eXBlb2Ygc2VsZi5pbXBvcnRTY3JpcHRzPT0iZnVuY3Rpb24iKSgpLEY9e2lzQnJvd3NlcjohMCxjbGFzc2VzOntVUkxTZWFyY2hQYXJhbXM6a3QsRm9ybURhdGE6RHQsQmxvYjpGdH0saXNTdGFuZGFyZEJyb3dzZXJFbnY6ZmksaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY6Y2kscHJvdG9jb2xzOlsiaHR0cCIsImh0dHBzIiwiZmlsZSIsImJsb2IiLCJ1cmwiLCJkYXRhIl19O2Z1bmN0aW9uIEtlKGUsQSl7cmV0dXJuIEooZSxuZXcgRi5jbGFzc2VzLlVSTFNlYXJjaFBhcmFtcyxPYmplY3QuYXNzaWduKHt2aXNpdG9yOmZ1bmN0aW9uKHQscixhLG8pe3JldHVybiBGLmlzTm9kZSYmYy5pc0J1ZmZlcih0KT8odGhpcy5hcHBlbmQocix0LnRvU3RyaW5nKCJiYXNlNjQiKSksITEpOm8uZGVmYXVsdFZpc2l0b3IuYXBwbHkodGhpcyxhcmd1bWVudHMpfX0sQSkpfWZ1bmN0aW9uIGRpKGUpe3JldHVybiBjLm1hdGNoQWxsKC9cdyt8XFsoXHcqKV0vZyxlKS5tYXAoQT0+QVswXT09PSJbXSI/IiI6QVsxXXx8QVswXSl9ZnVuY3Rpb24gQmkoZSl7bGV0IEE9e30sdD1PYmplY3Qua2V5cyhlKSxyLGE9dC5sZW5ndGgsbztmb3Iocj0wO3I8YTtyKyspbz10W3JdLEFbb109ZVtvXTtyZXR1cm4gQX1mdW5jdGlvbiBDaShlKXtmdW5jdGlvbiBBKHQscixhLG8pe2xldCBpPXRbbysrXSxsPU51bWJlci5pc0Zpbml0ZSgraSksZj1vPj10Lmxlbmd0aDtyZXR1cm4gaT0haSYmYy5pc0FycmF5KGEpP2EubGVuZ3RoOmksZj8oYy5oYXNPd25Qcm9wKGEsaSk/YVtpXT1bYVtpXSxyXTphW2ldPXIsIWwpOigoIWFbaV18fCFjLmlzT2JqZWN0KGFbaV0pKSYmKGFbaV09W10pLEEodCxyLGFbaV0sbykmJmMuaXNBcnJheShhW2ldKSYmKGFbaV09QmkoYVtpXSkpLCFsKX1pZihjLmlzRm9ybURhdGEoZSkmJmMuaXNGdW5jdGlvbihlLmVudHJpZXMpKXtsZXQgdD17fTtyZXR1cm4gYy5mb3JFYWNoRW50cnkoZSwocixhKT0+e0EoZGkociksYSx0LDApfSksdH1yZXR1cm4gbnVsbH12YXIgUWU9Q2k7ZnVuY3Rpb24geWkoZSxBLHQpe2lmKGMuaXNTdHJpbmcoZSkpdHJ5e3JldHVybihBfHxKU09OLnBhcnNlKShlKSxjLnRyaW0oZSl9Y2F0Y2gocil7aWYoci5uYW1lIT09IlN5bnRheEVycm9yIil0aHJvdyByfXJldHVybih0fHxKU09OLnN0cmluZ2lmeSkoZSl9dmFyIGplPXt0cmFuc2l0aW9uYWw6RWUsYWRhcHRlcjpbInhociIsImh0dHAiXSx0cmFuc2Zvcm1SZXF1ZXN0OltmdW5jdGlvbihBLHQpe2xldCByPXQuZ2V0Q29udGVudFR5cGUoKXx8IiIsYT1yLmluZGV4T2YoImFwcGxpY2F0aW9uL2pzb24iKT4tMSxvPWMuaXNPYmplY3QoQSk7aWYobyYmYy5pc0hUTUxGb3JtKEEpJiYoQT1uZXcgRm9ybURhdGEoQSkpLGMuaXNGb3JtRGF0YShBKSlyZXR1cm4gYSYmYT9KU09OLnN0cmluZ2lmeShRZShBKSk6QTtpZihjLmlzQXJyYXlCdWZmZXIoQSl8fGMuaXNCdWZmZXIoQSl8fGMuaXNTdHJlYW0oQSl8fGMuaXNGaWxlKEEpfHxjLmlzQmxvYihBKSlyZXR1cm4gQTtpZihjLmlzQXJyYXlCdWZmZXJWaWV3KEEpKXJldHVybiBBLmJ1ZmZlcjtpZihjLmlzVVJMU2VhcmNoUGFyYW1zKEEpKXJldHVybiB0LnNldENvbnRlbnRUeXBlKCJhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQ7Y2hhcnNldD11dGYtOCIsITEpLEEudG9TdHJpbmcoKTtsZXQgbDtpZihvKXtpZihyLmluZGV4T2YoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIpPi0xKXJldHVybiBLZShBLHRoaXMuZm9ybVNlcmlhbGl6ZXIpLnRvU3RyaW5nKCk7aWYoKGw9Yy5pc0ZpbGVMaXN0KEEpKXx8ci5pbmRleE9mKCJtdWx0aXBhcnQvZm9ybS1kYXRhIik+LTEpe2xldCBmPXRoaXMuZW52JiZ0aGlzLmVudi5Gb3JtRGF0YTtyZXR1cm4gSihsP3siZmlsZXNbXSI6QX06QSxmJiZuZXcgZix0aGlzLmZvcm1TZXJpYWxpemVyKX19cmV0dXJuIG98fGE/KHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL2pzb24iLCExKSx5aShBKSk6QX1dLHRyYW5zZm9ybVJlc3BvbnNlOltmdW5jdGlvbihBKXtsZXQgdD10aGlzLnRyYW5zaXRpb25hbHx8amUudHJhbnNpdGlvbmFsLHI9dCYmdC5mb3JjZWRKU09OUGFyc2luZyxhPXRoaXMucmVzcG9uc2VUeXBlPT09Impzb24iO2lmKEEmJmMuaXNTdHJpbmcoQSkmJihyJiYhdGhpcy5yZXNwb25zZVR5cGV8fGEpKXtsZXQgaT0hKHQmJnQuc2lsZW50SlNPTlBhcnNpbmcpJiZhO3RyeXtyZXR1cm4gSlNPTi5wYXJzZShBKX1jYXRjaChsKXtpZihpKXRocm93IGwubmFtZT09PSJTeW50YXhFcnJvciI/aC5mcm9tKGwsaC5FUlJfQkFEX1JFU1BPTlNFLHRoaXMsbnVsbCx0aGlzLnJlc3BvbnNlKTpsfX1yZXR1cm4gQX1dLHRpbWVvdXQ6MCx4c3JmQ29va2llTmFtZToiWFNSRi1UT0tFTiIseHNyZkhlYWRlck5hbWU6IlgtWFNSRi1UT0tFTiIsbWF4Q29udGVudExlbmd0aDotMSxtYXhCb2R5TGVuZ3RoOi0xLGVudjp7Rm9ybURhdGE6Ri5jbGFzc2VzLkZvcm1EYXRhLEJsb2I6Ri5jbGFzc2VzLkJsb2J9LHZhbGlkYXRlU3RhdHVzOmZ1bmN0aW9uKEEpe3JldHVybiBBPj0yMDAmJkE8MzAwfSxoZWFkZXJzOntjb21tb246e0FjY2VwdDoiYXBwbGljYXRpb24vanNvbiwgdGV4dC9wbGFpbiwgKi8qIiwiQ29udGVudC1UeXBlIjp2b2lkIDB9fX07Yy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsInBvc3QiLCJwdXQiLCJwYXRjaCJdLGU9PntqZS5oZWFkZXJzW2VdPXt9fSk7dmFyIHo9amU7dmFyIEVpPWMudG9PYmplY3RTZXQoWyJhZ2UiLCJhdXRob3JpemF0aW9uIiwiY29udGVudC1sZW5ndGgiLCJjb250ZW50LXR5cGUiLCJldGFnIiwiZXhwaXJlcyIsImZyb20iLCJob3N0IiwiaWYtbW9kaWZpZWQtc2luY2UiLCJpZi11bm1vZGlmaWVkLXNpbmNlIiwibGFzdC1tb2RpZmllZCIsImxvY2F0aW9uIiwibWF4LWZvcndhcmRzIiwicHJveHktYXV0aG9yaXphdGlvbiIsInJlZmVyZXIiLCJyZXRyeS1hZnRlciIsInVzZXItYWdlbnQiXSksT3Q9ZT0+e2xldCBBPXt9LHQscixhO3JldHVybiBlJiZlLnNwbGl0KGAKYCkuZm9yRWFjaChmdW5jdGlvbihpKXthPWkuaW5kZXhPZigiOiIpLHQ9aS5zdWJzdHJpbmcoMCxhKS50cmltKCkudG9Mb3dlckNhc2UoKSxyPWkuc3Vic3RyaW5nKGErMSkudHJpbSgpLCEoIXR8fEFbdF0mJkVpW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/QVt0XT9BW3RdLnB1c2gocik6QVt0XT1bcl06QVt0XT1BW3RdP0FbdF0rIiwgIityOnIpfSksQX07dmFyIFV0PVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gc2UoZSl7cmV0dXJuIGUmJlN0cmluZyhlKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiBoZShlKXtyZXR1cm4gZT09PSExfHxlPT1udWxsP2U6Yy5pc0FycmF5KGUpP2UubWFwKGhlKTpTdHJpbmcoZSl9ZnVuY3Rpb24gUWkoZSl7bGV0IEE9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15ccyw7PV0rKVxzKig/Oj1ccyooW14sO10rKSk/L2cscjtmb3IoO3I9dC5leGVjKGUpOylBW3JbMV1dPXJbMl07cmV0dXJuIEF9dmFyIGhpPWU9Pi9eWy1fYS16QS1aMC05XmB8fiwhIyQlJicqKy5dKyQvLnRlc3QoZS50cmltKCkpO2Z1bmN0aW9uIF9lKGUsQSx0LHIsYSl7aWYoYy5pc0Z1bmN0aW9uKHIpKXJldHVybiByLmNhbGwodGhpcyxBLHQpO2lmKGEmJihBPXQpLCEhYy5pc1N0cmluZyhBKSl7aWYoYy5pc1N0cmluZyhyKSlyZXR1cm4gQS5pbmRleE9mKHIpIT09LTE7aWYoYy5pc1JlZ0V4cChyKSlyZXR1cm4gci50ZXN0KEEpfX1mdW5jdGlvbiB3aShlKXtyZXR1cm4gZS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxkXSkoXHcqKS9nLChBLHQscik9PnQudG9VcHBlckNhc2UoKStyKX1mdW5jdGlvbiBSaShlLEEpe2xldCB0PWMudG9DYW1lbENhc2UoIiAiK0EpO1siZ2V0Iiwic2V0IiwiaGFzIl0uZm9yRWFjaChyPT57T2JqZWN0LmRlZmluZVByb3BlcnR5KGUscit0LHt2YWx1ZTpmdW5jdGlvbihhLG8saSl7cmV0dXJuIHRoaXNbcl0uY2FsbCh0aGlzLEEsYSxvLGkpfSxjb25maWd1cmFibGU6ITB9KX0pfXZhciBWPWNsYXNze2NvbnN0cnVjdG9yKEEpe0EmJnRoaXMuc2V0KEEpfXNldChBLHQscil7bGV0IGE9dGhpcztmdW5jdGlvbiBvKGwsZixnKXtsZXQgbj1zZShmKTtpZighbil0aHJvdyBuZXcgRXJyb3IoImhlYWRlciBuYW1lIG11c3QgYmUgYSBub24tZW1wdHkgc3RyaW5nIik7bGV0IHU9Yy5maW5kS2V5KGEsbik7KCF1fHxhW3VdPT09dm9pZCAwfHxnPT09ITB8fGc9PT12b2lkIDAmJmFbdV0hPT0hMSkmJihhW3V8fGZdPWhlKGwpKX1sZXQgaT0obCxmKT0+Yy5mb3JFYWNoKGwsKGcsbik9Pm8oZyxuLGYpKTtyZXR1cm4gYy5pc1BsYWluT2JqZWN0KEEpfHxBIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3Rvcj9pKEEsdCk6Yy5pc1N0cmluZyhBKSYmKEE9QS50cmltKCkpJiYhaGkoQSk/aShPdChBKSx0KTpBIT1udWxsJiZvKHQsQSxyKSx0aGlzfWdldChBLHQpe2lmKEE9c2UoQSksQSl7bGV0IHI9Yy5maW5kS2V5KHRoaXMsQSk7aWYocil7bGV0IGE9dGhpc1tyXTtpZighdClyZXR1cm4gYTtpZih0PT09ITApcmV0dXJuIFFpKGEpO2lmKGMuaXNGdW5jdGlvbih0KSlyZXR1cm4gdC5jYWxsKHRoaXMsYSxyKTtpZihjLmlzUmVnRXhwKHQpKXJldHVybiB0LmV4ZWMoYSk7dGhyb3cgbmV3IFR5cGVFcnJvcigicGFyc2VyIG11c3QgYmUgYm9vbGVhbnxyZWdleHB8ZnVuY3Rpb24iKX19fWhhcyhBLHQpe2lmKEE9c2UoQSksQSl7bGV0IHI9Yy5maW5kS2V5KHRoaXMsQSk7cmV0dXJuISEociYmdGhpc1tyXSE9PXZvaWQgMCYmKCF0fHxfZSh0aGlzLHRoaXNbcl0scix0KSkpfXJldHVybiExfWRlbGV0ZShBLHQpe2xldCByPXRoaXMsYT0hMTtmdW5jdGlvbiBvKGkpe2lmKGk9c2UoaSksaSl7bGV0IGw9Yy5maW5kS2V5KHIsaSk7bCYmKCF0fHxfZShyLHJbbF0sbCx0KSkmJihkZWxldGUgcltsXSxhPSEwKX19cmV0dXJuIGMuaXNBcnJheShBKT9BLmZvckVhY2gobyk6byhBKSxhfWNsZWFyKEEpe2xldCB0PU9iamVjdC5rZXlzKHRoaXMpLHI9dC5sZW5ndGgsYT0hMTtmb3IoO3ItLTspe2xldCBvPXRbcl07KCFBfHxfZSh0aGlzLHRoaXNbb10sbyxBLCEwKSkmJihkZWxldGUgdGhpc1tvXSxhPSEwKX1yZXR1cm4gYX1ub3JtYWxpemUoQSl7bGV0IHQ9dGhpcyxyPXt9O3JldHVybiBjLmZvckVhY2godGhpcywoYSxvKT0+e2xldCBpPWMuZmluZEtleShyLG8pO2lmKGkpe3RbaV09aGUoYSksZGVsZXRlIHRbb107cmV0dXJufWxldCBsPUE/d2kobyk6U3RyaW5nKG8pLnRyaW0oKTtsIT09byYmZGVsZXRlIHRbb10sdFtsXT1oZShhKSxyW2xdPSEwfSksdGhpc31jb25jYXQoLi4uQSl7cmV0dXJuIHRoaXMuY29uc3RydWN0b3IuY29uY2F0KHRoaXMsLi4uQSl9dG9KU09OKEEpe2xldCB0PU9iamVjdC5jcmVhdGUobnVsbCk7cmV0dXJuIGMuZm9yRWFjaCh0aGlzLChyLGEpPT57ciE9bnVsbCYmciE9PSExJiYodFthXT1BJiZjLmlzQXJyYXkocik/ci5qb2luKCIsICIpOnIpfSksdH1bU3ltYm9sLml0ZXJhdG9yXSgpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKVtTeW1ib2wuaXRlcmF0b3JdKCl9dG9TdHJpbmcoKXtyZXR1cm4gT2JqZWN0LmVudHJpZXModGhpcy50b0pTT04oKSkubWFwKChbQSx0XSk9PkErIjogIit0KS5qb2luKGAKYCl9Z2V0W1N5bWJvbC50b1N0cmluZ1RhZ10oKXtyZXR1cm4iQXhpb3NIZWFkZXJzIn1zdGF0aWMgZnJvbShBKXtyZXR1cm4gQSBpbnN0YW5jZW9mIHRoaXM/QTpuZXcgdGhpcyhBKX1zdGF0aWMgY29uY2F0KEEsLi4udCl7bGV0IHI9bmV3IHRoaXMoQSk7cmV0dXJuIHQuZm9yRWFjaChhPT5yLnNldChhKSkscn1zdGF0aWMgYWNjZXNzb3IoQSl7bGV0IHI9KHRoaXNbVXRdPXRoaXNbVXRdPXthY2Nlc3NvcnM6e319KS5hY2Nlc3NvcnMsYT10aGlzLnByb3RvdHlwZTtmdW5jdGlvbiBvKGkpe2xldCBsPXNlKGkpO3JbbF18fChSaShhLGkpLHJbbF09ITApfXJldHVybiBjLmlzQXJyYXkoQSk/QS5mb3JFYWNoKG8pOm8oQSksdGhpc319O1YuYWNjZXNzb3IoWyJDb250ZW50LVR5cGUiLCJDb250ZW50LUxlbmd0aCIsIkFjY2VwdCIsIkFjY2VwdC1FbmNvZGluZyIsIlVzZXItQWdlbnQiLCJBdXRob3JpemF0aW9uIl0pO2MucmVkdWNlRGVzY3JpcHRvcnMoVi5wcm90b3R5cGUsKHt2YWx1ZTplfSxBKT0+e2xldCB0PUFbMF0udG9VcHBlckNhc2UoKStBLnNsaWNlKDEpO3JldHVybntnZXQ6KCk9PmUsc2V0KHIpe3RoaXNbdF09cn19fSk7Yy5mcmVlemVNZXRob2RzKFYpO3ZhciBVPVY7ZnVuY3Rpb24gSWUoZSxBKXtsZXQgdD10aGlzfHx6LHI9QXx8dCxhPVUuZnJvbShyLmhlYWRlcnMpLG89ci5kYXRhO3JldHVybiBjLmZvckVhY2goZSxmdW5jdGlvbihsKXtvPWwuY2FsbCh0LG8sYS5ub3JtYWxpemUoKSxBP0Euc3RhdHVzOnZvaWQgMCl9KSxhLm5vcm1hbGl6ZSgpLG99ZnVuY3Rpb24gbGUoZSl7cmV0dXJuISEoZSYmZS5fX0NBTkNFTF9fKX1mdW5jdGlvbiBTdChlLEEsdCl7aC5jYWxsKHRoaXMsZT8/ImNhbmNlbGVkIixoLkVSUl9DQU5DRUxFRCxBLHQpLHRoaXMubmFtZT0iQ2FuY2VsZWRFcnJvciJ9Yy5pbmhlcml0cyhTdCxoLHtfX0NBTkNFTF9fOiEwfSk7dmFyIEw9U3Q7ZnVuY3Rpb24gemUoZSxBLHQpe2xldCByPXQuY29uZmlnLnZhbGlkYXRlU3RhdHVzOyF0LnN0YXR1c3x8IXJ8fHIodC5zdGF0dXMpP2UodCk6QShuZXcgaCgiUmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgY29kZSAiK3Quc3RhdHVzLFtoLkVSUl9CQURfUkVRVUVTVCxoLkVSUl9CQURfUkVTUE9OU0VdW01hdGguZmxvb3IodC5zdGF0dXMvMTAwKS00XSx0LmNvbmZpZyx0LnJlcXVlc3QsdCkpfXZhciBXdD1GLmlzU3RhbmRhcmRCcm93c2VyRW52P2Z1bmN0aW9uKCl7cmV0dXJue3dyaXRlOmZ1bmN0aW9uKHQscixhLG8saSxsKXtsZXQgZj1bXTtmLnB1c2godCsiPSIrZW5jb2RlVVJJQ29tcG9uZW50KHIpKSxjLmlzTnVtYmVyKGEpJiZmLnB1c2goImV4cGlyZXM9IituZXcgRGF0ZShhKS50b0dNVFN0cmluZygpKSxjLmlzU3RyaW5nKG8pJiZmLnB1c2goInBhdGg9IitvKSxjLmlzU3RyaW5nKGkpJiZmLnB1c2goImRvbWFpbj0iK2kpLGw9PT0hMCYmZi5wdXNoKCJzZWN1cmUiKSxkb2N1bWVudC5jb29raWU9Zi5qb2luKCI7ICIpfSxyZWFkOmZ1bmN0aW9uKHQpe2xldCByPWRvY3VtZW50LmNvb2tpZS5tYXRjaChuZXcgUmVnRXhwKCIoXnw7XFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIHI/ZGVjb2RlVVJJQ29tcG9uZW50KHJbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBWZShlKXtyZXR1cm4vXihbYS16XVthLXpcZCtcLS5dKjopP1wvXC8vaS50ZXN0KGUpfWZ1bmN0aW9uIFplKGUsQSl7cmV0dXJuIEE/ZS5yZXBsYWNlKC9cLyskLywiIikrIi8iK0EucmVwbGFjZSgvXlwvKy8sIiIpOmV9ZnVuY3Rpb24gZ2UoZSxBKXtyZXR1cm4gZSYmIVZlKEEpP1plKGUsQSk6QX12YXIgTnQ9Ri5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBBPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIikscjtmdW5jdGlvbiBhKG8pe2xldCBpPW87cmV0dXJuIEEmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsaSksaT10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixpKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cPy8sIiIpOiIiLGhhc2g6dC5oYXNoP3QuaGFzaC5yZXBsYWNlKC9eIy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIHI9YSh3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oaSl7bGV0IGw9Yy5pc1N0cmluZyhpKT9hKGkpOmk7cmV0dXJuIGwucHJvdG9jb2w9PT1yLnByb3RvY29sJiZsLmhvc3Q9PT1yLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIFhlKGUpe2xldCBBPS9eKFstK1x3XXsxLDI1fSkoOj9cL1wvfDopLy5leGVjKGUpO3JldHVybiBBJiZBWzFdfHwiIn1mdW5jdGlvbiBiaShlLEEpe2U9ZXx8MTA7bGV0IHQ9bmV3IEFycmF5KGUpLHI9bmV3IEFycmF5KGUpLGE9MCxvPTAsaTtyZXR1cm4gQT1BIT09dm9pZCAwP0E6MWUzLGZ1bmN0aW9uKGYpe2xldCBnPURhdGUubm93KCksbj1yW29dO2l8fChpPWcpLHRbYV09ZixyW2FdPWc7bGV0IHU9byxwPTA7Zm9yKDt1IT09YTspcCs9dFt1KytdLHU9dSVlO2lmKGE9KGErMSklZSxhPT09byYmKG89KG8rMSklZSksZy1pPEEpcmV0dXJuO2xldCBzPW4mJmctbjtyZXR1cm4gcz9NYXRoLnJvdW5kKHAqMWUzL3MpOnZvaWQgMH19dmFyIFB0PWJpO2Z1bmN0aW9uIHh0KGUsQSl7bGV0IHQ9MCxyPVB0KDUwLDI1MCk7cmV0dXJuIGE9PntsZXQgbz1hLmxvYWRlZCxpPWEubGVuZ3RoQ29tcHV0YWJsZT9hLnRvdGFsOnZvaWQgMCxsPW8tdCxmPXIobCksZz1vPD1pO3Q9bztsZXQgbj17bG9hZGVkOm8sdG90YWw6aSxwcm9ncmVzczppP28vaTp2b2lkIDAsYnl0ZXM6bCxyYXRlOmZ8fHZvaWQgMCxlc3RpbWF0ZWQ6ZiYmaSYmZz8oaS1vKS9mOnZvaWQgMCxldmVudDphfTtuW0E/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsZShuKX19dmFyIGtpPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsR3Q9a2kmJmZ1bmN0aW9uKGUpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LHIpe2xldCBhPWUuZGF0YSxvPVUuZnJvbShlLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGk9ZS5yZXNwb25zZVR5cGUsbDtmdW5jdGlvbiBmKCl7ZS5jYW5jZWxUb2tlbiYmZS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShsKSxlLnNpZ25hbCYmZS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLGwpfWxldCBnO2MuaXNGb3JtRGF0YShhKSYmKEYuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEYuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/by5zZXRDb250ZW50VHlwZSghMSk6by5nZXRDb250ZW50VHlwZSgvXlxzKm11bHRpcGFydFwvZm9ybS1kYXRhLyk/Yy5pc1N0cmluZyhnPW8uZ2V0Q29udGVudFR5cGUoKSkmJm8uc2V0Q29udGVudFR5cGUoZy5yZXBsYWNlKC9eXHMqKG11bHRpcGFydFwvZm9ybS1kYXRhKTsrLywiJDEiKSk6by5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YSIpKTtsZXQgbj1uZXcgWE1MSHR0cFJlcXVlc3Q7aWYoZS5hdXRoKXtsZXQgST1lLmF1dGgudXNlcm5hbWV8fCIiLGQ9ZS5hdXRoLnBhc3N3b3JkP3VuZXNjYXBlKGVuY29kZVVSSUNvbXBvbmVudChlLmF1dGgucGFzc3dvcmQpKToiIjtvLnNldCgiQXV0aG9yaXphdGlvbiIsIkJhc2ljICIrYnRvYShJKyI6IitkKSl9bGV0IHU9Z2UoZS5iYXNlVVJMLGUudXJsKTtuLm9wZW4oZS5tZXRob2QudG9VcHBlckNhc2UoKSxuZSh1LGUucGFyYW1zLGUucGFyYW1zU2VyaWFsaXplciksITApLG4udGltZW91dD1lLnRpbWVvdXQ7ZnVuY3Rpb24gcCgpe2lmKCFuKXJldHVybjtsZXQgST1VLmZyb20oImdldEFsbFJlc3BvbnNlSGVhZGVycyJpbiBuJiZuLmdldEFsbFJlc3BvbnNlSGVhZGVycygpKSxFPXtkYXRhOiFpfHxpPT09InRleHQifHxpPT09Impzb24iP24ucmVzcG9uc2VUZXh0Om4ucmVzcG9uc2Usc3RhdHVzOm4uc3RhdHVzLHN0YXR1c1RleHQ6bi5zdGF0dXNUZXh0LGhlYWRlcnM6SSxjb25maWc6ZSxyZXF1ZXN0Om59O3plKGZ1bmN0aW9uKHcpe3QodyksZigpfSxmdW5jdGlvbih3KXtyKHcpLGYoKX0sRSksbj1udWxsfWlmKCJvbmxvYWRlbmQiaW4gbj9uLm9ubG9hZGVuZD1wOm4ub25yZWFkeXN0YXRlY2hhbmdlPWZ1bmN0aW9uKCl7IW58fG4ucmVhZHlTdGF0ZSE9PTR8fG4uc3RhdHVzPT09MCYmIShuLnJlc3BvbnNlVVJMJiZuLnJlc3BvbnNlVVJMLmluZGV4T2YoImZpbGU6Iik9PT0wKXx8c2V0VGltZW91dChwKX0sbi5vbmFib3J0PWZ1bmN0aW9uKCl7biYmKHIobmV3IGgoIlJlcXVlc3QgYWJvcnRlZCIsaC5FQ09OTkFCT1JURUQsZSxuKSksbj1udWxsKX0sbi5vbmVycm9yPWZ1bmN0aW9uKCl7cihuZXcgaCgiTmV0d29yayBFcnJvciIsaC5FUlJfTkVUV09SSyxlLG4pKSxuPW51bGx9LG4ub250aW1lb3V0PWZ1bmN0aW9uKCl7bGV0IGQ9ZS50aW1lb3V0PyJ0aW1lb3V0IG9mICIrZS50aW1lb3V0KyJtcyBleGNlZWRlZCI6InRpbWVvdXQgZXhjZWVkZWQiLEU9ZS50cmFuc2l0aW9uYWx8fEVlO2UudGltZW91dEVycm9yTWVzc2FnZSYmKGQ9ZS50aW1lb3V0RXJyb3JNZXNzYWdlKSxyKG5ldyBoKGQsRS5jbGFyaWZ5VGltZW91dEVycm9yP2guRVRJTUVET1VUOmguRUNPTk5BQk9SVEVELGUsbikpLG49bnVsbH0sRi5pc1N0YW5kYXJkQnJvd3NlckVudil7bGV0IEk9TnQodSkmJmUueHNyZkNvb2tpZU5hbWUmJld0LnJlYWQoZS54c3JmQ29va2llTmFtZSk7SSYmby5zZXQoZS54c3JmSGVhZGVyTmFtZSxJKX1hPT09dm9pZCAwJiZvLnNldENvbnRlbnRUeXBlKG51bGwpLCJzZXRSZXF1ZXN0SGVhZGVyImluIG4mJmMuZm9yRWFjaChvLnRvSlNPTigpLGZ1bmN0aW9uKGQsRSl7bi5zZXRSZXF1ZXN0SGVhZGVyKEUsZCl9KSxjLmlzVW5kZWZpbmVkKGUud2l0aENyZWRlbnRpYWxzKXx8KG4ud2l0aENyZWRlbnRpYWxzPSEhZS53aXRoQ3JlZGVudGlhbHMpLGkmJmkhPT0ianNvbiImJihuLnJlc3BvbnNlVHlwZT1lLnJlc3BvbnNlVHlwZSksdHlwZW9mIGUub25Eb3dubG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZuLmFkZEV2ZW50TGlzdGVuZXIoInByb2dyZXNzIix4dChlLm9uRG93bmxvYWRQcm9ncmVzcywhMCkpLHR5cGVvZiBlLm9uVXBsb2FkUHJvZ3Jlc3M9PSJmdW5jdGlvbiImJm4udXBsb2FkJiZuLnVwbG9hZC5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIseHQoZS5vblVwbG9hZFByb2dyZXNzKSksKGUuY2FuY2VsVG9rZW58fGUuc2lnbmFsKSYmKGw9ST0+e24mJihyKCFJfHxJLnR5cGU/bmV3IEwobnVsbCxlLG4pOkkpLG4uYWJvcnQoKSxuPW51bGwpfSxlLmNhbmNlbFRva2VuJiZlLmNhbmNlbFRva2VuLnN1YnNjcmliZShsKSxlLnNpZ25hbCYmKGUuc2lnbmFsLmFib3J0ZWQ/bCgpOmUuc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoImFib3J0IixsKSkpO2xldCBzPVhlKHUpO2lmKHMmJkYucHJvdG9jb2xzLmluZGV4T2Yocyk9PT0tMSl7cihuZXcgaCgiVW5zdXBwb3J0ZWQgcHJvdG9jb2wgIitzKyI6IixoLkVSUl9CQURfUkVRVUVTVCxlKSk7cmV0dXJufW4uc2VuZChhfHxudWxsKX0pfTt2YXIgJGU9e2h0dHA6Q2UseGhyOkd0fTtjLmZvckVhY2goJGUsKGUsQSk9PntpZihlKXt0cnl7T2JqZWN0LmRlZmluZVByb3BlcnR5KGUsIm5hbWUiLHt2YWx1ZTpBfSl9Y2F0Y2h7fU9iamVjdC5kZWZpbmVQcm9wZXJ0eShlLCJhZGFwdGVyTmFtZSIse3ZhbHVlOkF9KX19KTt2YXIgVHQ9ZT0+YC0gJHtlfWAsRGk9ZT0+Yy5pc0Z1bmN0aW9uKGUpfHxlPT09bnVsbHx8ZT09PSExLHdlPXtnZXRBZGFwdGVyOmU9PntlPWMuaXNBcnJheShlKT9lOltlXTtsZXR7bGVuZ3RoOkF9PWUsdCxyLGE9e307Zm9yKGxldCBvPTA7bzxBO28rKyl7dD1lW29dO2xldCBpO2lmKHI9dCwhRGkodCkmJihyPSRlWyhpPVN0cmluZyh0KSkudG9Mb3dlckNhc2UoKV0scj09PXZvaWQgMCkpdGhyb3cgbmV3IGgoYFVua25vd24gYWRhcHRlciAnJHtpfSdgKTtpZihyKWJyZWFrO2FbaXx8IiMiK29dPXJ9aWYoIXIpe2xldCBvPU9iamVjdC5lbnRyaWVzKGEpLm1hcCgoW2wsZl0pPT5gYWRhcHRlciAke2x9IGArKGY9PT0hMT8iaXMgbm90IHN1cHBvcnRlZCBieSB0aGUgZW52aXJvbm1lbnQiOiJpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZCIpKSxpPUE/by5sZW5ndGg+MT9gc2luY2UgOgpgK28ubWFwKFR0KS5qb2luKGAKYCk6IiAiK1R0KG9bMF0pOiJhcyBubyBhZGFwdGVyIHNwZWNpZmllZCI7dGhyb3cgbmV3IGgoIlRoZXJlIGlzIG5vIHN1aXRhYmxlIGFkYXB0ZXIgdG8gZGlzcGF0Y2ggdGhlIHJlcXVlc3QgIitpLCJFUlJfTk9UX1NVUFBPUlQiKX1yZXR1cm4gcn0sYWRhcHRlcnM6JGV9O2Z1bmN0aW9uIGVBKGUpe2lmKGUuY2FuY2VsVG9rZW4mJmUuY2FuY2VsVG9rZW4udGhyb3dJZlJlcXVlc3RlZCgpLGUuc2lnbmFsJiZlLnNpZ25hbC5hYm9ydGVkKXRocm93IG5ldyBMKG51bGwsZSl9ZnVuY3Rpb24gUmUoZSl7cmV0dXJuIGVBKGUpLGUuaGVhZGVycz1VLmZyb20oZS5oZWFkZXJzKSxlLmRhdGE9SWUuY2FsbChlLGUudHJhbnNmb3JtUmVxdWVzdCksWyJwb3N0IiwicHV0IiwicGF0Y2giXS5pbmRleE9mKGUubWV0aG9kKSE9PS0xJiZlLmhlYWRlcnMuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCIsITEpLHdlLmdldEFkYXB0ZXIoZS5hZGFwdGVyfHx6LmFkYXB0ZXIpKGUpLnRoZW4oZnVuY3Rpb24ocil7cmV0dXJuIGVBKGUpLHIuZGF0YT1JZS5jYWxsKGUsZS50cmFuc2Zvcm1SZXNwb25zZSxyKSxyLmhlYWRlcnM9VS5mcm9tKHIuaGVhZGVycykscn0sZnVuY3Rpb24ocil7cmV0dXJuIGxlKHIpfHwoZUEoZSksciYmci5yZXNwb25zZSYmKHIucmVzcG9uc2UuZGF0YT1JZS5jYWxsKGUsZS50cmFuc2Zvcm1SZXNwb25zZSxyLnJlc3BvbnNlKSxyLnJlc3BvbnNlLmhlYWRlcnM9VS5mcm9tKHIucmVzcG9uc2UuaGVhZGVycykpKSxQcm9taXNlLnJlamVjdChyKX0pfXZhciBKdD1lPT5lIGluc3RhbmNlb2YgVT9lLnRvSlNPTigpOmU7ZnVuY3Rpb24gRyhlLEEpe0E9QXx8e307bGV0IHQ9e307ZnVuY3Rpb24gcihnLG4sdSl7cmV0dXJuIGMuaXNQbGFpbk9iamVjdChnKSYmYy5pc1BsYWluT2JqZWN0KG4pP2MubWVyZ2UuY2FsbCh7Y2FzZWxlc3M6dX0sZyxuKTpjLmlzUGxhaW5PYmplY3Qobik/Yy5tZXJnZSh7fSxuKTpjLmlzQXJyYXkobik/bi5zbGljZSgpOm59ZnVuY3Rpb24gYShnLG4sdSl7aWYoYy5pc1VuZGVmaW5lZChuKSl7aWYoIWMuaXNVbmRlZmluZWQoZykpcmV0dXJuIHIodm9pZCAwLGcsdSl9ZWxzZSByZXR1cm4gcihnLG4sdSl9ZnVuY3Rpb24gbyhnLG4pe2lmKCFjLmlzVW5kZWZpbmVkKG4pKXJldHVybiByKHZvaWQgMCxuKX1mdW5jdGlvbiBpKGcsbil7aWYoYy5pc1VuZGVmaW5lZChuKSl7aWYoIWMuaXNVbmRlZmluZWQoZykpcmV0dXJuIHIodm9pZCAwLGcpfWVsc2UgcmV0dXJuIHIodm9pZCAwLG4pfWZ1bmN0aW9uIGwoZyxuLHUpe2lmKHUgaW4gQSlyZXR1cm4gcihnLG4pO2lmKHUgaW4gZSlyZXR1cm4gcih2b2lkIDAsZyl9bGV0IGY9e3VybDpvLG1ldGhvZDpvLGRhdGE6byxiYXNlVVJMOmksdHJhbnNmb3JtUmVxdWVzdDppLHRyYW5zZm9ybVJlc3BvbnNlOmkscGFyYW1zU2VyaWFsaXplcjppLHRpbWVvdXQ6aSx0aW1lb3V0TWVzc2FnZTppLHdpdGhDcmVkZW50aWFsczppLGFkYXB0ZXI6aSxyZXNwb25zZVR5cGU6aSx4c3JmQ29va2llTmFtZTppLHhzcmZIZWFkZXJOYW1lOmksb25VcGxvYWRQcm9ncmVzczppLG9uRG93bmxvYWRQcm9ncmVzczppLGRlY29tcHJlc3M6aSxtYXhDb250ZW50TGVuZ3RoOmksbWF4Qm9keUxlbmd0aDppLGJlZm9yZVJlZGlyZWN0OmksdHJhbnNwb3J0OmksaHR0cEFnZW50OmksaHR0cHNBZ2VudDppLGNhbmNlbFRva2VuOmksc29ja2V0UGF0aDppLHJlc3BvbnNlRW5jb2Rpbmc6aSx2YWxpZGF0ZVN0YXR1czpsLGhlYWRlcnM6KGcsbik9PmEoSnQoZyksSnQobiksITApfTtyZXR1cm4gYy5mb3JFYWNoKE9iamVjdC5rZXlzKE9iamVjdC5hc3NpZ24oe30sZSxBKSksZnVuY3Rpb24obil7bGV0IHU9ZltuXXx8YSxwPXUoZVtuXSxBW25dLG4pO2MuaXNVbmRlZmluZWQocCkmJnUhPT1sfHwodFtuXT1wKX0pLHR9dmFyIGJlPSIxLjYuMCI7dmFyIEFBPXt9O1sib2JqZWN0IiwiYm9vbGVhbiIsIm51bWJlciIsImZ1bmN0aW9uIiwic3RyaW5nIiwic3ltYm9sIl0uZm9yRWFjaCgoZSxBKT0+e0FBW2VdPWZ1bmN0aW9uKHIpe3JldHVybiB0eXBlb2Ygcj09PWV8fCJhIisoQTwxPyJuICI6IiAiKStlfX0pO3ZhciBMdD17fTtBQS50cmFuc2l0aW9uYWw9ZnVuY3Rpb24oQSx0LHIpe2Z1bmN0aW9uIGEobyxpKXtyZXR1cm4iW0F4aW9zIHYiK2JlKyJdIFRyYW5zaXRpb25hbCBvcHRpb24gJyIrbysiJyIraSsocj8iLiAiK3I6IiIpfXJldHVybihvLGksbCk9PntpZihBPT09ITEpdGhyb3cgbmV3IGgoYShpLCIgaGFzIGJlZW4gcmVtb3ZlZCIrKHQ/IiBpbiAiK3Q6IiIpKSxoLkVSUl9ERVBSRUNBVEVEKTtyZXR1cm4gdCYmIUx0W2ldJiYoTHRbaV09ITAsY29uc29sZS53YXJuKGEoaSwiIGhhcyBiZWVuIGRlcHJlY2F0ZWQgc2luY2UgdiIrdCsiIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gdGhlIG5lYXIgZnV0dXJlIikpKSxBP0EobyxpLGwpOiEwfX07ZnVuY3Rpb24gRmkoZSxBLHQpe2lmKHR5cGVvZiBlIT0ib2JqZWN0Iil0aHJvdyBuZXcgaCgib3B0aW9ucyBtdXN0IGJlIGFuIG9iamVjdCIsaC5FUlJfQkFEX09QVElPTl9WQUxVRSk7bGV0IHI9T2JqZWN0LmtleXMoZSksYT1yLmxlbmd0aDtmb3IoO2EtLSA+MDspe2xldCBvPXJbYV0saT1BW29dO2lmKGkpe2xldCBsPWVbb10sZj1sPT09dm9pZCAwfHxpKGwsbyxlKTtpZihmIT09ITApdGhyb3cgbmV3IGgoIm9wdGlvbiAiK28rIiBtdXN0IGJlICIrZixoLkVSUl9CQURfT1BUSU9OX1ZBTFVFKTtjb250aW51ZX1pZih0IT09ITApdGhyb3cgbmV3IGgoIlVua25vd24gb3B0aW9uICIrbyxoLkVSUl9CQURfT1BUSU9OKX19dmFyIGtlPXthc3NlcnRPcHRpb25zOkZpLHZhbGlkYXRvcnM6QUF9O3ZhciBNPWtlLnZhbGlkYXRvcnMsWj1jbGFzc3tjb25zdHJ1Y3RvcihBKXt0aGlzLmRlZmF1bHRzPUEsdGhpcy5pbnRlcmNlcHRvcnM9e3JlcXVlc3Q6bmV3IHZlLHJlc3BvbnNlOm5ldyB2ZX19cmVxdWVzdChBLHQpe3R5cGVvZiBBPT0ic3RyaW5nIj8odD10fHx7fSx0LnVybD1BKTp0PUF8fHt9LHQ9Ryh0aGlzLmRlZmF1bHRzLHQpO2xldHt0cmFuc2l0aW9uYWw6cixwYXJhbXNTZXJpYWxpemVyOmEsaGVhZGVyczpvfT10O3IhPT12b2lkIDAmJmtlLmFzc2VydE9wdGlvbnMocix7c2lsZW50SlNPTlBhcnNpbmc6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKSxmb3JjZWRKU09OUGFyc2luZzpNLnRyYW5zaXRpb25hbChNLmJvb2xlYW4pLGNsYXJpZnlUaW1lb3V0RXJyb3I6TS50cmFuc2l0aW9uYWwoTS5ib29sZWFuKX0sITEpLGEhPW51bGwmJihjLmlzRnVuY3Rpb24oYSk/dC5wYXJhbXNTZXJpYWxpemVyPXtzZXJpYWxpemU6YX06a2UuYXNzZXJ0T3B0aW9ucyhhLHtlbmNvZGU6TS5mdW5jdGlvbixzZXJpYWxpemU6TS5mdW5jdGlvbn0sITApKSx0Lm1ldGhvZD0odC5tZXRob2R8fHRoaXMuZGVmYXVsdHMubWV0aG9kfHwiZ2V0IikudG9Mb3dlckNhc2UoKTtsZXQgaT1vJiZjLm1lcmdlKG8uY29tbW9uLG9bdC5tZXRob2RdKTtvJiZjLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sST0+e2RlbGV0ZSBvW0ldfSksdC5oZWFkZXJzPVUuY29uY2F0KGksbyk7bGV0IGw9W10sZj0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZCl7dHlwZW9mIGQucnVuV2hlbj09ImZ1bmN0aW9uIiYmZC5ydW5XaGVuKHQpPT09ITF8fChmPWYmJmQuc3luY2hyb25vdXMsbC51bnNoaWZ0KGQuZnVsZmlsbGVkLGQucmVqZWN0ZWQpKX0pO2xldCBnPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZCl7Zy5wdXNoKGQuZnVsZmlsbGVkLGQucmVqZWN0ZWQpfSk7bGV0IG4sdT0wLHA7aWYoIWYpe2xldCBJPVtSZS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKEkudW5zaGlmdC5hcHBseShJLGwpLEkucHVzaC5hcHBseShJLGcpLHA9SS5sZW5ndGgsbj1Qcm9taXNlLnJlc29sdmUodCk7dTxwOyluPW4udGhlbihJW3UrK10sSVt1KytdKTtyZXR1cm4gbn1wPWwubGVuZ3RoO2xldCBzPXQ7Zm9yKHU9MDt1PHA7KXtsZXQgST1sW3UrK10sZD1sW3UrK107dHJ5e3M9SShzKX1jYXRjaChFKXtkLmNhbGwodGhpcyxFKTticmVha319dHJ5e249UmUuY2FsbCh0aGlzLHMpfWNhdGNoKEkpe3JldHVybiBQcm9taXNlLnJlamVjdChJKX1mb3IodT0wLHA9Zy5sZW5ndGg7dTxwOyluPW4udGhlbihnW3UrK10sZ1t1KytdKTtyZXR1cm4gbn1nZXRVcmkoQSl7QT1HKHRoaXMuZGVmYXVsdHMsQSk7bGV0IHQ9Z2UoQS5iYXNlVVJMLEEudXJsKTtyZXR1cm4gbmUodCxBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpfX07Yy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihBKXtaLnByb3RvdHlwZVtBXT1mdW5jdGlvbih0LHIpe3JldHVybiB0aGlzLnJlcXVlc3QoRyhyfHx7fSx7bWV0aG9kOkEsdXJsOnQsZGF0YToocnx8e30pLmRhdGF9KSl9fSk7Yy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oQSl7ZnVuY3Rpb24gdChyKXtyZXR1cm4gZnVuY3Rpb24obyxpLGwpe3JldHVybiB0aGlzLnJlcXVlc3QoRyhsfHx7fSx7bWV0aG9kOkEsaGVhZGVyczpyP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDpvLGRhdGE6aX0pKX19Wi5wcm90b3R5cGVbQV09dCgpLFoucHJvdG90eXBlW0ErIkZvcm0iXT10KCEwKX0pO3ZhciBwZT1aO3ZhciB0QT1jbGFzcyBle2NvbnN0cnVjdG9yKEEpe2lmKHR5cGVvZiBBIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24obyl7dD1vfSk7bGV0IHI9dGhpczt0aGlzLnByb21pc2UudGhlbihhPT57aWYoIXIuX2xpc3RlbmVycylyZXR1cm47bGV0IG89ci5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO28tLSA+MDspci5fbGlzdGVuZXJzW29dKGEpO3IuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49YT0+e2xldCBvLGk9bmV3IFByb21pc2UobD0+e3Iuc3Vic2NyaWJlKGwpLG89bH0pLnRoZW4oYSk7cmV0dXJuIGkuY2FuY2VsPWZ1bmN0aW9uKCl7ci51bnN1YnNjcmliZShvKX0saX0sQShmdW5jdGlvbihvLGksbCl7ci5yZWFzb258fChyLnJlYXNvbj1uZXcgTChvLGksbCksdChyLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShBKXtpZih0aGlzLnJlYXNvbil7QSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChBKTp0aGlzLl9saXN0ZW5lcnM9W0FdfXVuc3Vic2NyaWJlKEEpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKEEpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgQTtyZXR1cm57dG9rZW46bmV3IGUoZnVuY3Rpb24oYSl7QT1hfSksY2FuY2VsOkF9fX0sTXQ9dEE7ZnVuY3Rpb24gckEoZSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBlLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGlBKGUpe3JldHVybiBjLmlzT2JqZWN0KGUpJiZlLmlzQXhpb3NFcnJvcj09PSEwfXZhciBhQT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXMoYUEpLmZvckVhY2goKFtlLEFdKT0+e2FBW0FdPWV9KTt2YXIgSHQ9YUE7ZnVuY3Rpb24gWXQoZSl7bGV0IEE9bmV3IHBlKGUpLHQ9aWUocGUucHJvdG90eXBlLnJlcXVlc3QsQSk7cmV0dXJuIGMuZXh0ZW5kKHQscGUucHJvdG90eXBlLEEse2FsbE93bktleXM6ITB9KSxjLmV4dGVuZCh0LEEsbnVsbCx7YWxsT3duS2V5czohMH0pLHQuY3JlYXRlPWZ1bmN0aW9uKGEpe3JldHVybiBZdChHKGUsYSkpfSx0fXZhciBiPVl0KHopO2IuQXhpb3M9cGU7Yi5DYW5jZWxlZEVycm9yPUw7Yi5DYW5jZWxUb2tlbj1NdDtiLmlzQ2FuY2VsPWxlO2IuVkVSU0lPTj1iZTtiLnRvRm9ybURhdGE9SjtiLkF4aW9zRXJyb3I9aDtiLkNhbmNlbD1iLkNhbmNlbGVkRXJyb3I7Yi5hbGw9ZnVuY3Rpb24oQSl7cmV0dXJuIFByb21pc2UuYWxsKEEpfTtiLnNwcmVhZD1yQTtiLmlzQXhpb3NFcnJvcj1pQTtiLm1lcmdlQ29uZmlnPUc7Yi5BeGlvc0hlYWRlcnM9VTtiLmZvcm1Ub0pTT049ZT0+UWUoYy5pc0hUTUxGb3JtKGUpP25ldyBGb3JtRGF0YShlKTplKTtiLmdldEFkYXB0ZXI9d2UuZ2V0QWRhcHRlcjtiLkh0dHBTdGF0dXNDb2RlPUh0O2IuZGVmYXVsdD1iO3ZhciBZPWI7dmFye0F4aW9zOnNJLEF4aW9zRXJyb3I6SUksQ2FuY2VsZWRFcnJvcjpsSSxpc0NhbmNlbDpnSSxDYW5jZWxUb2tlbjpwSSxWRVJTSU9OOm1JLGFsbDp1SSxDYW5jZWw6ZkksaXNBeGlvc0Vycm9yOmNJLHNwcmVhZDpkSSx0b0Zvcm1EYXRhOkJJLEF4aW9zSGVhZGVyczpDSSxIdHRwU3RhdHVzQ29kZTp5SSxmb3JtVG9KU09OOkVJLGdldEFkYXB0ZXI6UUksbWVyZ2VDb25maWc6aEl9PVk7dmFyIHZ0PVN5bWJvbCgiQ29tbGluay5wcm94eSIpLE9pPVN5bWJvbCgiQ29tbGluay5lbmRwb2ludCIpLHNBPVN5bWJvbCgiQ29tbGluay5yZWxlYXNlUHJveHkiKSxvQT1TeW1ib2woIkNvbWxpbmsuZmluYWxpemVyIiksRmU9U3ltYm9sKCJDb21saW5rLnRocm93biIpLEt0PWU9PnR5cGVvZiBlPT0ib2JqZWN0IiYmZSE9PW51bGx8fHR5cGVvZiBlPT0iZnVuY3Rpb24iLFVpPXtjYW5IYW5kbGU6ZT0+S3QoZSkmJmVbdnRdLHNlcmlhbGl6ZShlKXtsZXR7cG9ydDE6QSxwb3J0Mjp0fT1uZXcgTWVzc2FnZUNoYW5uZWw7cmV0dXJuIF90KGUsQSksW3QsW3RdXX0sZGVzZXJpYWxpemUoZSl7cmV0dXJuIGUuc3RhcnQoKSxJQShlKX19LFNpPXtjYW5IYW5kbGU6ZT0+S3QoZSkmJkZlIGluIGUsc2VyaWFsaXplKHt2YWx1ZTplfSl7bGV0IEE7cmV0dXJuIGUgaW5zdGFuY2VvZiBFcnJvcj9BPXtpc0Vycm9yOiEwLHZhbHVlOnttZXNzYWdlOmUubWVzc2FnZSxuYW1lOmUubmFtZSxzdGFjazplLnN0YWNrfX06QT17aXNFcnJvcjohMSx2YWx1ZTplfSxbQSxbXV19LGRlc2VyaWFsaXplKGUpe3Rocm93IGUuaXNFcnJvcj9PYmplY3QuYXNzaWduKG5ldyBFcnJvcihlLnZhbHVlLm1lc3NhZ2UpLGUudmFsdWUpOmUudmFsdWV9fSxqdD1uZXcgTWFwKFtbInByb3h5IixVaV0sWyJ0aHJvdyIsU2ldXSk7ZnVuY3Rpb24gV2koZSxBKXtmb3IobGV0IHQgb2YgZSlpZihBPT09dHx8dD09PSIqInx8dCBpbnN0YW5jZW9mIFJlZ0V4cCYmdC50ZXN0KEEpKXJldHVybiEwO3JldHVybiExfWZ1bmN0aW9uIF90KGUsQT1nbG9iYWxUaGlzLHQ9WyIqIl0pe0EuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gcihhKXtpZighYXx8IWEuZGF0YSlyZXR1cm47aWYoIVdpKHQsYS5vcmlnaW4pKXtjb25zb2xlLndhcm4oYEludmFsaWQgb3JpZ2luICcke2Eub3JpZ2lufScgZm9yIGNvbWxpbmsgcHJveHlgKTtyZXR1cm59bGV0e2lkOm8sdHlwZTppLHBhdGg6bH09T2JqZWN0LmFzc2lnbih7cGF0aDpbXX0sYS5kYXRhKSxmPShhLmRhdGEuYXJndW1lbnRMaXN0fHxbXSkubWFwKHEpLGc7dHJ5e2xldCBuPWwuc2xpY2UoMCwtMSkucmVkdWNlKChwLHMpPT5wW3NdLGUpLHU9bC5yZWR1Y2UoKHAscyk9PnBbc10sZSk7c3dpdGNoKGkpe2Nhc2UiR0VUIjpnPXU7YnJlYWs7Y2FzZSJTRVQiOm5bbC5zbGljZSgtMSlbMF1dPXEoYS5kYXRhLnZhbHVlKSxnPSEwO2JyZWFrO2Nhc2UiQVBQTFkiOmc9dS5hcHBseShuLGYpO2JyZWFrO2Nhc2UiQ09OU1RSVUNUIjp7bGV0IHA9bmV3IHUoLi4uZik7Zz1UaShwKX1icmVhaztjYXNlIkVORFBPSU5UIjp7bGV0e3BvcnQxOnAscG9ydDI6c309bmV3IE1lc3NhZ2VDaGFubmVsO190KGUscyksZz1sQShwLFtwXSl9YnJlYWs7Y2FzZSJSRUxFQVNFIjpnPXZvaWQgMDticmVhaztkZWZhdWx0OnJldHVybn19Y2F0Y2gobil7Zz17dmFsdWU6bixbRmVdOjB9fVByb21pc2UucmVzb2x2ZShnKS5jYXRjaChuPT4oe3ZhbHVlOm4sW0ZlXTowfSkpLnRoZW4obj0+e2xldFt1LHBdPVNlKG4pO0EucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LHUpLHtpZDpvfSkscCksaT09PSJSRUxFQVNFIiYmKEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsciksenQoQSksb0EgaW4gZSYmdHlwZW9mIGVbb0FdPT0iZnVuY3Rpb24iJiZlW29BXSgpKX0pLmNhdGNoKG49PntsZXRbdSxwXT1TZSh7dmFsdWU6bmV3IFR5cGVFcnJvcigiVW5zZXJpYWxpemFibGUgcmV0dXJuIHZhbHVlIiksW0ZlXTowfSk7QS5wb3N0TWVzc2FnZShPYmplY3QuYXNzaWduKE9iamVjdC5hc3NpZ24oe30sdSkse2lkOm99KSxwKX0pfSksQS5zdGFydCYmQS5zdGFydCgpfWZ1bmN0aW9uIE5pKGUpe3JldHVybiBlLmNvbnN0cnVjdG9yLm5hbWU9PT0iTWVzc2FnZVBvcnQifWZ1bmN0aW9uIHp0KGUpe05pKGUpJiZlLmNsb3NlKCl9ZnVuY3Rpb24gSUEoZSxBKXtyZXR1cm4gbkEoZSxbXSxBKX1mdW5jdGlvbiBEZShlKXtpZihlKXRocm93IG5ldyBFcnJvcigiUHJveHkgaGFzIGJlZW4gcmVsZWFzZWQgYW5kIGlzIG5vdCB1c2VhYmxlIil9ZnVuY3Rpb24gVnQoZSl7cmV0dXJuIFgoZSx7dHlwZToiUkVMRUFTRSJ9KS50aGVuKCgpPT57enQoZSl9KX12YXIgT2U9bmV3IFdlYWtNYXAsVWU9IkZpbmFsaXphdGlvblJlZ2lzdHJ5ImluIGdsb2JhbFRoaXMmJm5ldyBGaW5hbGl6YXRpb25SZWdpc3RyeShlPT57bGV0IEE9KE9lLmdldChlKXx8MCktMTtPZS5zZXQoZSxBKSxBPT09MCYmVnQoZSl9KTtmdW5jdGlvbiBQaShlLEEpe2xldCB0PShPZS5nZXQoQSl8fDApKzE7T2Uuc2V0KEEsdCksVWUmJlVlLnJlZ2lzdGVyKGUsQSxlKX1mdW5jdGlvbiB4aShlKXtVZSYmVWUudW5yZWdpc3RlcihlKX1mdW5jdGlvbiBuQShlLEE9W10sdD1mdW5jdGlvbigpe30pe2xldCByPSExLGE9bmV3IFByb3h5KHQse2dldChvLGkpe2lmKERlKHIpLGk9PT1zQSlyZXR1cm4oKT0+e3hpKGEpLFZ0KGUpLHI9ITB9O2lmKGk9PT0idGhlbiIpe2lmKEEubGVuZ3RoPT09MClyZXR1cm57dGhlbjooKT0+YX07bGV0IGw9WChlLHt0eXBlOiJHRVQiLHBhdGg6QS5tYXAoZj0+Zi50b1N0cmluZygpKX0pLnRoZW4ocSk7cmV0dXJuIGwudGhlbi5iaW5kKGwpfXJldHVybiBuQShlLFsuLi5BLGldKX0sc2V0KG8saSxsKXtEZShyKTtsZXRbZixnXT1TZShsKTtyZXR1cm4gWChlLHt0eXBlOiJTRVQiLHBhdGg6Wy4uLkEsaV0ubWFwKG49Pm4udG9TdHJpbmcoKSksdmFsdWU6Zn0sZykudGhlbihxKX0sYXBwbHkobyxpLGwpe0RlKHIpO2xldCBmPUFbQS5sZW5ndGgtMV07aWYoZj09PU9pKXJldHVybiBYKGUse3R5cGU6IkVORFBPSU5UIn0pLnRoZW4ocSk7aWYoZj09PSJiaW5kIilyZXR1cm4gbkEoZSxBLnNsaWNlKDAsLTEpKTtsZXRbZyxuXT1xdChsKTtyZXR1cm4gWChlLHt0eXBlOiJBUFBMWSIscGF0aDpBLm1hcCh1PT51LnRvU3RyaW5nKCkpLGFyZ3VtZW50TGlzdDpnfSxuKS50aGVuKHEpfSxjb25zdHJ1Y3QobyxpKXtEZShyKTtsZXRbbCxmXT1xdChpKTtyZXR1cm4gWChlLHt0eXBlOiJDT05TVFJVQ1QiLHBhdGg6QS5tYXAoZz0+Zy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6bH0sZikudGhlbihxKX19KTtyZXR1cm4gUGkoYSxlKSxhfWZ1bmN0aW9uIEdpKGUpe3JldHVybiBBcnJheS5wcm90b3R5cGUuY29uY2F0LmFwcGx5KFtdLGUpfWZ1bmN0aW9uIHF0KGUpe2xldCBBPWUubWFwKFNlKTtyZXR1cm5bQS5tYXAodD0+dFswXSksR2koQS5tYXAodD0+dFsxXSkpXX12YXIgWnQ9bmV3IFdlYWtNYXA7ZnVuY3Rpb24gbEEoZSxBKXtyZXR1cm4gWnQuc2V0KGUsQSksZX1mdW5jdGlvbiBUaShlKXtyZXR1cm4gT2JqZWN0LmFzc2lnbihlLHtbdnRdOiEwfSl9ZnVuY3Rpb24gU2UoZSl7Zm9yKGxldFtBLHRdb2YganQpaWYodC5jYW5IYW5kbGUoZSkpe2xldFtyLGFdPXQuc2VyaWFsaXplKGUpO3JldHVyblt7dHlwZToiSEFORExFUiIsbmFtZTpBLHZhbHVlOnJ9LGFdfXJldHVyblt7dHlwZToiUkFXIix2YWx1ZTplfSxadC5nZXQoZSl8fFtdXX1mdW5jdGlvbiBxKGUpe3N3aXRjaChlLnR5cGUpe2Nhc2UiSEFORExFUiI6cmV0dXJuIGp0LmdldChlLm5hbWUpLmRlc2VyaWFsaXplKGUudmFsdWUpO2Nhc2UiUkFXIjpyZXR1cm4gZS52YWx1ZX19ZnVuY3Rpb24gWChlLEEsdCl7cmV0dXJuIG5ldyBQcm9taXNlKHI9PntsZXQgYT1KaSgpO2UuYWRkRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsZnVuY3Rpb24gbyhpKXshaS5kYXRhfHwhaS5kYXRhLmlkfHxpLmRhdGEuaWQhPT1hfHwoZS5yZW1vdmVFdmVudExpc3RlbmVyKCJtZXNzYWdlIixvKSxyKGkuZGF0YSkpfSksZS5zdGFydCYmZS5zdGFydCgpLGUucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbih7aWQ6YX0sQSksdCl9KX1mdW5jdGlvbiBKaSgpe3JldHVybiBuZXcgQXJyYXkoNCkuZmlsbCgwKS5tYXAoKCk9Pk1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSpOdW1iZXIuTUFYX1NBRkVfSU5URUdFUikudG9TdHJpbmcoMTYpKS5qb2luKCItIil9ZnVuY3Rpb24gJHQoZSl7bGV0IEE9SUEoZSksdD1lO3JldHVybiB0LndvcmtlclByb3h5PUEsdC5vcmlnaW5hbFRlcm1pbmF0ZT10LnRlcm1pbmF0ZSx0LnRlcm1pbmF0ZT0oKT0+e3Qud29ya2VyUHJveHlbc0FdKCksdC5vcmlnaW5hbFRlcm1pbmF0ZSgpfSx7d29ya2VyUHJveHk6QSx3b3JrZXI6dH19YXN5bmMgZnVuY3Rpb24gTGkoZSxBKXtsZXQgdDtpZihlIT1udWxsKXtsZXQgaT1lO3JldHVybiBpLndvcmtlclByb3h5IT09dm9pZCAwPyh0PWkud29ya2VyUHJveHkse3dvcmtlclByb3h5OnQsd29ya2VyOml9KTokdChlKX1sZXQgcj10eXBlb2YgQT4idSI/di5waXBlbGluZVdvcmtlclVybDpBLGE9bnVsbCxvPXYud2ViV29ya2Vyc1VybDtpZih0eXBlb2YgbzwidSIpe2NvbnNvbGUud2FybigiaXRrQ29uZmlnIHdlYldvcmtlcnNVcmwgaXMgZGVwcmVjYXRlZC4gUGxlYXNlIHVzZSBwaXBlbGluZVdvcmtlclVybCB3aXRoIHRoZSBmdWxsIHBhdGggdG8gdGhlIHBpcGVsaW5lIHdvcmtlci4iKTtsZXQgaT0ibWluLiIsbD1vO2lmKGwuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgZj1hd2FpdCBZLmdldChgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHtyZXNwb25zZVR5cGU6ImJsb2IifSksZz1VUkwuY3JlYXRlT2JqZWN0VVJMKGYuZGF0YSk7YT1uZXcgV29ya2VyKGcse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIGE9bmV3IFdvcmtlcihgJHtsfS9idW5kbGVzL3BpcGVsaW5lLiR7aX13b3JrZXIuanNgLHt0eXBlOiJtb2R1bGUifSl9ZWxzZSBpZihyPT09bnVsbClhPW5ldyBXb3JrZXIobmV3IFVSTCgiLi93ZWItd29ya2Vycy9pdGstd2FzbS1waXBlbGluZS53b3JrZXIuanMiLGltcG9ydC5tZXRhLnVybCkse3R5cGU6Im1vZHVsZSJ9KTtlbHNlIGlmKHIuc3RhcnRzV2l0aCgiaHR0cCIpKXtsZXQgaT1hd2FpdCBZLmdldChyLHtyZXNwb25zZVR5cGU6ImJsb2IifSksbD1VUkwuY3JlYXRlT2JqZWN0VVJMKGkuZGF0YSk7YT1uZXcgV29ya2VyKGwse3R5cGU6Im1vZHVsZSJ9KX1lbHNlIGE9bmV3IFdvcmtlcihyLHt0eXBlOiJtb2R1bGUifSk7cmV0dXJuICR0KGEpfXZhciBlcj1MaTt2YXIgTWk7ZnVuY3Rpb24gQXIoKXtyZXR1cm4gTWl9dmFyIEhpO2Z1bmN0aW9uIHRyKCl7cmV0dXJuIEhpfWZ1bmN0aW9uIFlpKGUpe2xldCBBPWUuc2xpY2UoKGUubGFzdEluZGV4T2YoIi4iKS0xPj4+MCkrMik7aWYoQS50b0xvd2VyQ2FzZSgpPT09Imd6Iil7bGV0IHQ9ZS5zbGljZSgwLC0zKS5sYXN0SW5kZXhPZigiLiIpO0E9ZS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihBLnRvTG93ZXJDYXNlKCk9PT0iY2JvciIpe2xldCB0PWUuc2xpY2UoMCwtNSkubGFzdEluZGV4T2YoIi4iKTtBPWUuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoQS50b0xvd2VyQ2FzZSgpPT09InpzdCIpe2xldCB0PWUuc2xpY2UoMCwtMTApLmxhc3RJbmRleE9mKCIuIik7QT1lLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKEEudG9Mb3dlckNhc2UoKT09PSJ6aXAiKXtsZXQgdD1lLnNsaWNlKDAsLTQpLmxhc3RJbmRleE9mKCIuIik7QT1lLnNsaWNlKCh0LTE+Pj4wKSsyKX1yZXR1cm4gQX12YXIgbWU9WWk7ZnVuY3Rpb24gcWkoZSl7cmV0dXJuW2UuZGF0YSxlLmRpcmVjdGlvbl19dmFyIGdBPXFpO2Z1bmN0aW9uIHZpKGUpe3JldHVybltlLnBvaW50cyxlLnBvaW50RGF0YSxlLmNlbGxzLGUuY2VsbERhdGFdfXZhciBycj12aTthc3luYyBmdW5jdGlvbiBLaShlLEEpe2xldCB0PSJ1bmtub3duIjt0eXBlb2YgZSE9InN0cmluZyI/dD1lLmhyZWY6ZS5zdGFydHNXaXRoKCJodHRwIik/dD1lOnQ9YCR7QX0vJHtlfWAsdC5lbmRzV2l0aCgiLmpzIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtMykpLHQuZW5kc1dpdGgoIi53YXNtIikmJih0PXQuc3Vic3RyaW5nKDAsdC5sZW5ndGgtNSkpO2xldCByPWAke3R9Lndhc21gLG89KGF3YWl0IFkuZ2V0KHIse3Jlc3BvbnNlVHlwZToiYXJyYXlidWZmZXIifSkpLmRhdGE7cmV0dXJuKGF3YWl0IGltcG9ydChgJHt0fS5qc2ApKS5kZWZhdWx0KHt3YXNtQmluYXJ5Om99KX12YXIgaXI9S2k7dmFyIGFyPWFzeW5jKCk9PldlYkFzc2VtYmx5LnZhbGlkYXRlKG5ldyBVaW50OEFycmF5KFswLDk3LDExNSwxMDksMSwwLDAsMCwxLDUsMSw5NiwwLDEsMTIzLDMsMiwxLDAsMTAsMTAsMSw4LDAsNjUsMCwyNTMsMTUsMjUzLDk4LDExXSkpO3ZhciBzcj10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixvcj1uZXcgVGV4dEVuY29kZXIsbnI9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoZSxBKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxyPWUuZnNfb3BlbihBLHQuZmxhZ3MpLG89ZS5mc19zdGF0KEEpLnNpemUsaT1udWxsO3NyP2k9bmV3IFNoYXJlZEFycmF5QnVmZmVyKG8pOmk9bmV3IEFycmF5QnVmZmVyKG8pO2xldCBsPW5ldyBVaW50OEFycmF5KGkpO3JldHVybiBlLmZzX3JlYWQocixsLDAsbywwKSxlLmZzX2Nsb3NlKHIpLGx9ZnVuY3Rpb24gSXIoZSxBLHQpe2xldCByPW51bGw7c3I/cj1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6cj1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IGE9bmV3IFVpbnQ4QXJyYXkociksbz1uZXcgVWludDhBcnJheShlLkhFQVBVOC5idWZmZXIsQSx0KTtyZXR1cm4gYS5zZXQobyksYX1mdW5jdGlvbiBPKGUsQSx0LHIpe2xldCBhPTA7cmV0dXJuIEEhPT1udWxsJiYoYT1lLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LHIsQS5idWZmZXIuYnl0ZUxlbmd0aF0pLGUuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShBLmJ1ZmZlciksYSkpLGF9ZnVuY3Rpb24gJChlLEEsdCl7bGV0IHI9SlNPTi5zdHJpbmdpZnkoQSksYT1lLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsci5sZW5ndGhdKTtlLndyaXRlQXNjaWlUb01lbW9yeShyLGEsITEpfWZ1bmN0aW9uIE4oZSxBLHQscil7bGV0IGE9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQSx0XSksbz1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxBLHRdKSxpPUlyKGUsYSxvKTtyZXR1cm4gRChyLGkuYnVmZmVyKX1mdW5jdGlvbiBwQShlLEEpe2xldCB0PWUuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsQV0pLHI9ZS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKHIpfWZ1bmN0aW9uIGppKGUsQSx0LHIpe3IhPW51bGwmJnIubGVuZ3RoPjAmJnIuZm9yRWFjaChmdW5jdGlvbihnLG4pe3ZhciB1O3N3aXRjaChnLnR5cGUpe2Nhc2UgbS5UZXh0U3RyZWFtOntsZXQgcD1vci5lbmNvZGUoZy5kYXRhLmRhdGEpLHM9TyhlLHAsbiwwKSxJPXtzaXplOnAuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3N9YH07JChlLEksbik7YnJlYWt9Y2FzZSBtLkpzb25Db21wYXRpYmxlOntsZXQgcD1vci5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoZy5kYXRhKSkscz1PKGUscCxuLDApLEk9e3NpemU6cC5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7c31gfTskKGUsSSxuKTticmVha31jYXNlIG0uQmluYXJ5U3RyZWFtOntsZXQgcD1nLmRhdGEuZGF0YSxzPU8oZSxwLG4sMCksST17c2l6ZTpwLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWB9OyQoZSxJLG4pO2JyZWFrfWNhc2UgbS5UZXh0RmlsZTp7ZS5mc193cml0ZUZpbGUoZy5kYXRhLnBhdGgsZy5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgbS5CaW5hcnlGaWxlOntlLmZzX3dyaXRlRmlsZShnLmRhdGEucGF0aCxnLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSBtLkltYWdlOntsZXQgcD1nLmRhdGEscz1PKGUscC5kYXRhLG4sMCksST1PKGUscC5kaXJlY3Rpb24sbiwxKSxkPXR5cGVvZigodT1wLm1ldGFkYXRhKT09PW51bGx8fHU9PT12b2lkIDA/dm9pZCAwOnUuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20ocC5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLEU9e2ltYWdlVHlwZTpwLmltYWdlVHlwZSxuYW1lOnAubmFtZSxvcmlnaW46cC5vcmlnaW4sc3BhY2luZzpwLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLHNpemU6cC5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWAsbWV0YWRhdGE6ZH07JChlLEUsbik7YnJlYWt9Y2FzZSBtLk1lc2g6e2xldCBwPWcuZGF0YSxzPU8oZSxwLnBvaW50cyxuLDApLEk9TyhlLHAuY2VsbHMsbiwxKSxkPU8oZSxwLnBvaW50RGF0YSxuLDIpLEU9TyhlLHAuY2VsbERhdGEsbiwzKSxSPXttZXNoVHlwZTpwLm1lc2hUeXBlLG5hbWU6cC5uYW1lLG51bWJlck9mUG9pbnRzOnAubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7c31gLG51bWJlck9mQ2VsbHM6cC5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLGNlbGxCdWZmZXJTaXplOnAuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczpwLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7ZH1gLG51bWJlck9mQ2VsbFBpeGVsczpwLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0V9YH07JChlLFIsbik7YnJlYWt9Y2FzZSBtLlBvbHlEYXRhOntsZXQgcD1nLmRhdGEscz1PKGUscC5wb2ludHMsbiwwKSxJPU8oZSxwLnZlcnRpY2VzLG4sMSksZD1PKGUscC5saW5lcyxuLDIpLEU9TyhlLHAucG9seWdvbnMsbiwzKSxSPU8oZSxwLnRyaWFuZ2xlU3RyaXBzLG4sNCksdz1PKGUscC5wb2ludERhdGEsbiw1KSxrPU8oZSxwLnBvaW50RGF0YSxuLDYpLFdlPXtwb2x5RGF0YVR5cGU6cC5wb2x5RGF0YVR5cGUsbmFtZTpwLm5hbWUsbnVtYmVyT2ZQb2ludHM6cC5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtzfWAsdmVydGljZXNCdWZmZXJTaXplOnAudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7SX1gLGxpbmVzQnVmZmVyU2l6ZTpwLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2R9YCxwb2x5Z29uc0J1ZmZlclNpemU6cC5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtFfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOnAudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Un1gLG51bWJlck9mUG9pbnRQaXhlbHM6cC5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke3d9YCxudW1iZXJPZkNlbGxQaXhlbHM6cC5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtrfWB9OyQoZSxXZSxuKTticmVha31jYXNlIFcuVGV4dDp7ZS5mc193cml0ZUZpbGUoZy5wYXRoLGcuZGF0YSk7YnJlYWt9Y2FzZSBXLkJpbmFyeTp7ZS5mc193cml0ZUZpbGUoZy5wYXRoLGcuZGF0YSk7YnJlYWt9Y2FzZSBXLkltYWdlOntsZXQgcD1nLmRhdGEscz17aW1hZ2VUeXBlOnAuaW1hZ2VUeXBlLG5hbWU6cC5uYW1lLG9yaWdpbjpwLm9yaWdpbixzcGFjaW5nOnAuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTpwLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKGUuZnNfbWtkaXJzKGAke2cucGF0aH0vZGF0YWApLGUuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkocykpLHAuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkocC5kYXRhLmJ1ZmZlcikpLGUuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShwLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFcuTWVzaDp7bGV0IHA9Zy5kYXRhLHM9e21lc2hUeXBlOnAubWVzaFR5cGUsbmFtZTpwLm5hbWUsbnVtYmVyT2ZQb2ludHM6cC5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczpwLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6cC5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOnAubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6cC5jZWxsQnVmZmVyU2l6ZX07aWYoZS5mc19ta2RpcnMoYCR7Zy5wYXRofS9kYXRhYCksZS5mc193cml0ZUZpbGUoYCR7Zy5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShzKSkscy5udW1iZXJPZlBvaW50cz4wKXtpZihwLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtlLmZzX3dyaXRlRmlsZShgJHtnLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkocC5wb2ludHMuYnVmZmVyKSl9aWYocy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKHAucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShwLnBvaW50RGF0YS5idWZmZXIpKX1pZihzLm51bWJlck9mQ2VsbHM+MCl7aWYocC5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KHAuY2VsbHMuYnVmZmVyKSl9aWYocy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYocC5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO2UuZnNfd3JpdGVGaWxlKGAke2cucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KHAuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLGUucmVzZXRNb2R1bGVTdGRvdXQoKSxlLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IGE9ZS5zdGFja1NhdmUoKSxvPTA7dHJ5e289ZS5jYWxsTWFpbihBLnNsaWNlKCkpfWNhdGNoKGcpe3Rocm93IHR5cGVvZiBnPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsZS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsZS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIGUuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsZS5nZXRFeGNlcHRpb25NZXNzYWdlKGcpKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLGd9ZmluYWxseXtlLnN0YWNrUmVzdG9yZShhKX1sZXQgaT1lLmdldE1vZHVsZVN0ZG91dCgpLGw9ZS5nZXRNb2R1bGVTdGRlcnIoKSxmPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZvPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKGcsbil7bGV0IHU9bnVsbDtzd2l0Y2goZy50eXBlKXtjYXNlIG0uVGV4dFN0cmVhbTp7bGV0IHM9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbiwwXSksST1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxuLDBdKSxkPW5ldyBVaW50OEFycmF5KGUuSEVBUFU4LmJ1ZmZlcixzLEkpO3U9e2RhdGE6bnIuZGVjb2RlKGQpfTticmVha31jYXNlIG0uSnNvbkNvbXBhdGlibGU6e2xldCBzPWUuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG4sMF0pLEk9ZS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsbiwwXSksZD1uZXcgVWludDhBcnJheShlLkhFQVBVOC5idWZmZXIscyxJKTt1PUpTT04ucGFyc2UobnIuZGVjb2RlKGQpKTticmVha31jYXNlIG0uQmluYXJ5U3RyZWFtOntsZXQgcz1lLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxuLDBdKSxJPWUuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLG4sMF0pO3U9e2RhdGE6SXIoZSxzLEkpfTticmVha31jYXNlIG0uVGV4dEZpbGU6e3U9e3BhdGg6Zy5kYXRhLnBhdGgsZGF0YTplLmZzX3JlYWRGaWxlKGcuZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSBtLkJpbmFyeUZpbGU6e3U9e3BhdGg6Zy5kYXRhLnBhdGgsZGF0YTpIKGUsZy5kYXRhLnBhdGgpfTticmVha31jYXNlIG0uSW1hZ2U6e2xldCBzPXBBKGUsbik7cy5kYXRhPU4oZSxuLDAscy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSkscy5kaXJlY3Rpb249TihlLG4sMSxTLkZsb2F0NjQpLHMubWV0YWRhdGE9bmV3IE1hcChzLm1ldGFkYXRhKSx1PXM7YnJlYWt9Y2FzZSBtLk1lc2g6e2xldCBzPXBBKGUsbik7cy5udW1iZXJPZlBvaW50cz4wP3MucG9pbnRzPU4oZSxuLDAscy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOnMucG9pbnRzPUQocy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzLm51bWJlck9mQ2VsbHM+MD9zLmNlbGxzPU4oZSxuLDEscy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6cy5jZWxscz1EKHMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxzLm51bWJlck9mUG9pbnRQaXhlbHM+MD9zLnBvaW50RGF0YT1OKGUsbiwyLHMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOnMucG9pbnREYXRhPUQocy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/cy5jZWxsRGF0YT1OKGUsbiwzLHMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6cy5jZWxsRGF0YT1EKHMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLHU9czticmVha31jYXNlIG0uUG9seURhdGE6e2xldCBzPXBBKGUsbik7cy5udW1iZXJPZlBvaW50cz4wP3MucG9pbnRzPU4oZSxuLDAsUy5GbG9hdDMyKTpzLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LHMudmVydGljZXNCdWZmZXJTaXplPjA/cy52ZXJ0aWNlcz1OKGUsbiwxLFEuVUludDMyKTpzLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxzLmxpbmVzQnVmZmVyU2l6ZT4wP3MubGluZXM9TihlLG4sMixRLlVJbnQzMik6cy5saW5lcz1uZXcgVWludDMyQXJyYXkscy5wb2x5Z29uc0J1ZmZlclNpemU+MD9zLnBvbHlnb25zPU4oZSxuLDMsUS5VSW50MzIpOnMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LHMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/cy50cmlhbmdsZVN0cmlwcz1OKGUsbiw0LFEuVUludDMyKTpzLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxzLm51bWJlck9mUG9pbnRQaXhlbHM+MD9zLnBvaW50RGF0YT1OKGUsbiw1LHMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpzLnBvaW50RGF0YT1EKHMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSkscy5udW1iZXJPZkNlbGxQaXhlbHM+MD9zLmNlbGxEYXRhPU4oZSxuLDYscy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6cy5jZWxsRGF0YT1EKHMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSx1PXM7YnJlYWt9Y2FzZSBXLlRleHQ6e2lmKHR5cGVvZiBnLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTt1PWUuZnNfcmVhZEZpbGUoZy5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFcuQmluYXJ5OntpZih0eXBlb2YgZy5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7dT1IKGUsZy5wYXRoKTticmVha31jYXNlIFcuSW1hZ2U6e2lmKHR5cGVvZiBnLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgcz1lLmZzX3JlYWRGaWxlKGAke2cucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLEk9SlNPTi5wYXJzZShzKSxkPUgoZSxgJHtnLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtJLmRhdGE9RChJLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGQuYnVmZmVyKTtsZXQgRT1IKGUsYCR7Zy5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtJLmRpcmVjdGlvbj1EKFMuRmxvYXQ2NCxFLmJ1ZmZlciksdT1JO2JyZWFrfWNhc2UgVy5NZXNoOntpZih0eXBlb2YgZy5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IHM9ZS5mc19yZWFkRmlsZShgJHtnLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxJPUpTT04ucGFyc2Uocyk7aWYoSS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZD1IKGUsYCR7Zy5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtJLnBvaW50cz1EKEkubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkucG9pbnRzPUQoSS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihJLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGQ9SChlLGAke2cucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7SS5wb2ludERhdGE9RChJLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkucG9pbnREYXRhPUQoSS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKEkubnVtYmVyT2ZDZWxscz4wKXtsZXQgZD1IKGUsYCR7Zy5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO0kuY2VsbHM9RChJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkuY2VsbHM9RChJLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoSS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGQ9SChlLGAke2cucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtJLmNlbGxEYXRhPUQoSS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGQuYnVmZmVyKX1lbHNlIEkuY2VsbERhdGE9RChJLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTt1PUk7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgcD17dHlwZTpnLnR5cGUsZGF0YTp1fTtmLnB1c2gocCl9KSx7cmV0dXJuVmFsdWU6byxzdGRvdXQ6aSxzdGRlcnI6bCxvdXRwdXRzOmZ9fXZhciBscj1qaTt2YXIgbUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiBfaShlKXtsZXQgQT1lLHQ9ZTtpZih0eXBlb2YgZSE9InN0cmluZyImJihBPW5ldyBVUkwoZS5ocmVmKSx0PUEuaHJlZiksbUEuaGFzKHQpKXJldHVybiBtQS5nZXQodCk7e2xldCByPWF3YWl0IGlyKGUsdi5waXBlbGluZXNVcmwpO3JldHVybiBtQS5zZXQodCxyKSxyfX1hc3luYyBmdW5jdGlvbiB6aShlLEEsdCxyLGEsbyl7dmFyIGksbDtpZighYXdhaXQgYXIoKSl7bGV0IHc9IldlYkFzc2VtYmx5IFNJTUQgc3VwcG9ydCBpcyByZXF1aXJlZCAtLSBwbGVhc2UgdXBkYXRlIHlvdXIgYnJvd3Nlci4iO3Rocm93IGFsZXJ0KHcpLG5ldyBFcnJvcih3KX1pZihlPT09ITEpe2xldCB3PWF3YWl0IF9pKEEudG9TdHJpbmcoKSk7cmV0dXJuIGxyKHcsdCxyLGEpfWxldCBmPWUsZz0oaT1vPy5waXBlbGluZVdvcmtlclVybCkhPT1udWxsJiZpIT09dm9pZCAwP2k6bnVsbCxuPXR5cGVvZiBnIT0ic3RyaW5nIiYmdHlwZW9mIGc/LmhyZWY8InUiP2cuaHJlZjpnLHt3b3JrZXJQcm94eTp1LHdvcmtlcjpwfT1hd2FpdCBlcihmLG4pO2Y9cDtsZXQgcz1bXTthIT1udWxsJiZhLmxlbmd0aD4wJiZhLmZvckVhY2goZnVuY3Rpb24odyl7aWYody50eXBlPT09bS5CaW5hcnlTdHJlYW0pe2xldCBrPXcuZGF0YS5kYXRhO3MucHVzaChrKX1lbHNlIGlmKHcudHlwZT09PW0uQmluYXJ5RmlsZSl7bGV0IGs9dy5kYXRhLmRhdGE7cy5wdXNoKGspfWVsc2UgaWYody50eXBlPT09bS5JbWFnZSl7bGV0IGs9dy5kYXRhO2lmKGsuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlIGRhdGEgY2Fubm90IGJlIG51bGwiKTtzLnB1c2goLi4uZ0EoaykpfWVsc2UgaWYody50eXBlPT09Vy5CaW5hcnkpcy5wdXNoKHcuZGF0YSk7ZWxzZSBpZih3LnR5cGU9PT1XLkltYWdlKXtsZXQgaz13LmRhdGE7aWYoay5kYXRhPT09bnVsbCl0aHJvdyBFcnJvcigiaW1hZ2UgZGF0YSBjYW5ub3QgYmUgbnVsbCIpO3MucHVzaCguLi5nQShrKSl9ZWxzZSBpZih3LnR5cGU9PT1XLk1lc2gpe2xldCBrPXcuZGF0YTtzLnB1c2goLi4ucnIoaykpfX0pO2xldCBJPShsPW8/LnBpcGVsaW5lQmFzZVVybCkhPT1udWxsJiZsIT09dm9pZCAwP2w6InBpcGVsaW5lc1VybCIsZD10eXBlb2YgSSE9InN0cmluZyImJnR5cGVvZiBJPy5ocmVmPCJ1Ij9JLmhyZWY6SSxFPWEhPW51bGw/bEEoYSxsdChzKSk6bnVsbCxSPWF3YWl0IHUucnVuUGlwZWxpbmUodixBLnRvU3RyaW5nKCksZCx0LHIsRSk7cmV0dXJue3JldHVyblZhbHVlOlIucmV0dXJuVmFsdWUsc3Rkb3V0OlIuc3Rkb3V0LHN0ZGVycjpSLnN0ZGVycixvdXRwdXRzOlIub3V0cHV0cyx3ZWJXb3JrZXI6Zn19dmFyIEI9emk7dmFyIGdyPXtuYW1lOiJAaXRrLXdhc20vaW1hZ2UtaW8iLHZlcnNpb246IjAuNC4wIixkZXNjcmlwdGlvbjoiSW5wdXQgYW5kIG91dHB1dCBmb3Igc2NpZW50aWZpYyBhbmQgbWVkaWNhbCBpbWFnZSBmaWxlIGZvcm1hdHMuIix0eXBlOiJtb2R1bGUiLG1vZHVsZToiLi9kaXN0L2luZGV4LmpzIix0eXBlczoiLi9kaXN0L2luZGV4LmQudHMiLGV4cG9ydHM6eyIuIjp7dHlwZXM6Ii4vZGlzdC9pbmRleC5kLmpzIixicm93c2VyOiIuL2Rpc3QvaW5kZXguanMiLG5vZGU6Ii4vZGlzdC9pbmRleC1ub2RlLmpzIixkZWZhdWx0OiIuL2Rpc3QvaW5kZXguanMifX0sc2NyaXB0czp7c3RhcnQ6Im5wbSBydW4gY29weVNob2VsYWNlQXNzZXRzICYmIHZpdGUgLWMgYnVpbGQvdml0ZS5jb25maWcuanMiLHRlc3Q6Im5wbSBydW4gdGVzdDpub2RlICYmIG5wbSBydW4gdGVzdDpicm93c2VyIiwidGVzdDpub2RlIjoiYXZhIiwidGVzdDpicm93c2VyIjoibnBtIHJ1biB0ZXN0OmJyb3dzZXI6Y2hyb21lICYmIG5wbSBydW4gdGVzdDpicm93c2VyOmZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6ZmlyZWZveCI6InN0YXJ0LXNlcnZlci1hbmQtdGVzdCByb2xsdXA6c3RhcnQgaHR0cC1nZXQ6Ly9sb2NhbGhvc3Q6NTAwNCBjeXByZXNzOnJ1bkZpcmVmb3giLCJ0ZXN0OmJyb3dzZXI6Y2hyb21lIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHJvbGx1cDpzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MDA0IGN5cHJlc3M6cnVuQ2hyb21lIiwidGVzdDpicm93c2VyOmRlYnVnIjoic3RhcnQtc2VydmVyLWFuZC10ZXN0IHJvbGx1cDpzdGFydCBodHRwLWdldDovL2xvY2FsaG9zdDo1MDA0IGN5cHJlc3M6b3BlbiIsImN5cHJlc3M6b3BlbiI6Im5weCBjeXByZXNzIG9wZW4iLCJjeXByZXNzOnJ1bkNocm9tZSI6Im5weCBjeXByZXNzIHJ1biAtLWJyb3dzZXIgY2hyb21lIiwiY3lwcmVzczpydW5GaXJlZm94IjoibnB4IGN5cHJlc3MgcnVuIC0tYnJvd3NlciBmaXJlZm94IixidWlsZDoibnBtIHJ1biBidWlsZDp0c2MgJiYgbnBtIHJ1biBidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkICYmIG5wbSBydW4gYnVpbGQ6YnJvd3Nlcjp3b3JrZXJFbWJlZGRlZE1pbiAmJiBucG0gcnVuIGJ1aWxkOmRlbW8iLCJidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkIjoiZXNidWlsZCAtLWxvYWRlcjoud29ya2VyLmpzPWRhdGF1cmwgLS1idW5kbGUgLS1mb3JtYXQ9ZXNtIC0tb3V0ZmlsZT0uL2Rpc3QvYnVuZGxlL2luZGV4LXdvcmtlci1lbWJlZGRlZC5qcyAuL3NyYy9pbmRleC13b3JrZXItZW1iZWRkZWQudHMiLCJidWlsZDpicm93c2VyOndvcmtlckVtYmVkZGVkTWluIjoiZXNidWlsZCAtLW1pbmlmeSAtLWxvYWRlcjoud29ya2VyLmpzPWRhdGF1cmwgLS1idW5kbGUgLS1mb3JtYXQ9ZXNtIC0tb3V0ZmlsZT0uL2Rpc3QvYnVuZGxlL2luZGV4LXdvcmtlci1lbWJlZGRlZC5taW4uanMgLi9zcmMvaW5kZXgtd29ya2VyLWVtYmVkZGVkLm1pbi50cyIsImJ1aWxkOnRzYyI6InRzYyAtLXByZXR0eSIsY29weVNob2VsYWNlQXNzZXRzOiJzaHggbWtkaXIgLXAgdGVzdC9icm93c2VyL2RlbW8tYXBwL3B1YmxpYyAmJiBzaHggY3AgLXIgbm9kZV9tb2R1bGVzL0BzaG9lbGFjZS1zdHlsZS9zaG9lbGFjZS9kaXN0L2Fzc2V0cyB0ZXN0L2Jyb3dzZXIvZGVtby1hcHAvcHVibGljLyIsImJ1aWxkOmRlbW8iOiJucG0gcnVuIGNvcHlTaG9lbGFjZUFzc2V0cyAmJiB2aXRlIC1jIGJ1aWxkL3ZpdGUuY29uZmlnLmpzIGJ1aWxkIiwicm9sbHVwOnN0YXJ0IjoibnBtIHJ1biBjb3B5U2hvZWxhY2VBc3NldHMgJiYgbnBtIHJ1biBidWlsZDpkZW1vICYmIGNvbmN1cnJlbnRseSBucG06cm9sbHVwOmRldiBucG06cm9sbHVwOnByZXZpZXciLCJyb2xsdXA6ZGV2Ijoidml0ZSBidWlsZCAtLWNvbmZpZyBidWlsZC92aXRlLXJvbGx1cC13YXRjaC5jb25maWcudHMiLCJyb2xsdXA6cHJldmlldyI6InZpdGUgcHJldmlldyAtLWNvbmZpZyBidWlsZC92aXRlLXJvbGx1cC13YXRjaC5jb25maWcudHMifSxrZXl3b3JkczpbIml0ayIsIndhc20iLCJ3ZWJhc3NlbWJseSIsIndhc2kiXSxhdXRob3I6IiIsbGljZW5zZToiQXBhY2hlLTIuMCIsZGVwZW5kZW5jaWVzOnsiaXRrLXdhc20iOiJeMS4wLjAtYi4xNTQifSxkZXZEZXBlbmRlbmNpZXM6eyJAc2hvZWxhY2Utc3R5bGUvc2hvZWxhY2UiOiJeMi41LjIiLCJAdHlwZXMvbm9kZSI6Il4yMC4yLjUiLGF2YToiXjUuMy4xIixjb25jdXJyZW50bHk6Il44LjIuMSIsY3lwcmVzczoiXjEzLjMuMCIsZXNidWlsZDoiXjAuMTkuNSIsc2h4OiJeMC4zLjQiLCJzdGFydC1zZXJ2ZXItYW5kLXRlc3QiOiJeMi4wLjEiLHR5cGVzY3JpcHQ6Il41LjAuNCIsdml0ZToiXjQuNS4wIiwidml0ZS1wbHVnaW4tc3RhdGljLWNvcHkiOiJeMC4xNy4wIn0scmVwb3NpdG9yeTp7dHlwZToiZ2l0Iix1cmw6Imh0dHBzOi8vZ2l0aHViLmNvbS9JbnNpZ2h0U29mdHdhcmVDb25zb3J0aXVtL2l0ay13YXNtIn0sYXZhOntmaWxlczpbInRlc3Qvbm9kZS8qKi8qIiwiIXRlc3Qvbm9kZS9jb21tb24uanMiXX19O3ZhciB1QSxaaT1gaHR0cHM6Ly9jZG4uanNkZWxpdnIubmV0L25wbS9AaXRrLXdhc20vaW1hZ2UtaW9AJHtnci52ZXJzaW9ufS9kaXN0L3BpcGVsaW5lc2A7ZnVuY3Rpb24gcGwoZSl7dUE9ZX1mdW5jdGlvbiBDKCl7aWYodHlwZW9mIHVBPCJ1IilyZXR1cm4gdUE7bGV0IGU9dHIoKTtyZXR1cm4gdHlwZW9mIGU8InUiP2U6Wml9dmFyIGZBLFhpPW51bGw7ZnVuY3Rpb24gcHIoZSl7ZkE9ZX1mdW5jdGlvbiB5KCl7aWYodHlwZW9mIGZBPCJ1IilyZXR1cm4gZkE7bGV0IGU9QXIoKTtyZXR1cm4gdHlwZW9mIGU8InUiP2U6WGl9dmFyICRpPW5ldyBNYXAoW1siaW1hZ2UvanBlZyIsImpwZWciXSxbImltYWdlL3BuZyIsInBuZyJdLFsiaW1hZ2UvdGlmZiIsInRpZmYiXSxbImltYWdlL3gtbXMtYm1wIiwiYm1wIl0sWyJpbWFnZS94LWJtcCIsImJtcCJdLFsiaW1hZ2UvYm1wIiwiYm1wIl0sWyJhcHBsaWNhdGlvbi9kaWNvbSIsImdkY20iXV0pLGVlPSRpO3ZhciBlYT1uZXcgTWFwKFtbImJtcCIsImJtcCJdLFsiZGNtIiwiZ2RjbSJdLFsiZ2lwbCIsImdpcGwiXSxbImdpcGwuZ3oiLCJnaXBsIl0sWyJoZGY1IiwiaGRmNSJdLFsianBnIiwianBlZyJdLFsianBlZyIsImpwZWciXSxbIml3aSIsIndhc20iXSxbIml3aS5jYm9yIiwid2FzbSJdLFsiaXdpLmNib3IuenN0Iiwid2FzbVpzdGQiXSxbImxzbSIsImxzbSJdLFsibW5jIiwibW5jIl0sWyJtbmMuZ3oiLCJtbmMiXSxbIm1uYzIiLCJtbmMiXSxbIm1naCIsIm1naCJdLFsibWd6IiwibWdoIl0sWyJtZ2guZ3oiLCJtZ2giXSxbIm1oYSIsIm1ldGEiXSxbIm1oZCIsIm1ldGEiXSxbIm1yYyIsIm1yYyJdLFsibmlhIiwibmlmdGkiXSxbIm5paSIsIm5pZnRpIl0sWyJuaWkuZ3oiLCJuaWZ0aSJdLFsiaGRyIiwibmlmdGkiXSxbIm5ycmQiLCJucnJkIl0sWyJuaGRyIiwibnJyZCJdLFsicG5nIiwicG5nIl0sWyJwaWMiLCJiaW9SYWQiXSxbInRpZiIsInRpZmYiXSxbInRpZmYiLCJ0aWZmIl0sWyJ2dGsiLCJ2dGsiXSxbImlzcSIsInNjYW5jbyJdLFsiYWltIiwic2NhbmNvIl0sWyJmZGYiLCJmZGYiXV0pLEFlPWVhO2FzeW5jIGZ1bmN0aW9uIEFhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0icG5nLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBjQT1BYTthc3luYyBmdW5jdGlvbiB0YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InBuZy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgZEE9dGE7YXN5bmMgZnVuY3Rpb24gcmEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJtZXRhLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBCQT1yYTthc3luYyBmdW5jdGlvbiBpYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1ldGEtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIENBPWlhO2FzeW5jIGZ1bmN0aW9uIGFhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0idGlmZi1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgeUE9YWE7YXN5bmMgZnVuY3Rpb24gb2EoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ0aWZmLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBFQT1vYTthc3luYyBmdW5jdGlvbiBuYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Im5pZnRpLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBRQT1uYTthc3luYyBmdW5jdGlvbiBzYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im5pZnRpLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBoQT1zYTthc3luYyBmdW5jdGlvbiBJYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImpwZWctcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHdBPUlhO2FzeW5jIGZ1bmN0aW9uIGxhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0ianBlZy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgUkE9bGE7YXN5bmMgZnVuY3Rpb24gZ2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJucnJkLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBiQT1nYTthc3luYyBmdW5jdGlvbiBwYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im5ycmQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIGtBPXBhO2FzeW5jIGZ1bmN0aW9uIG1hKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0idnRrLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBEQT1tYTthc3luYyBmdW5jdGlvbiB1YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InZ0ay13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgRkE9dWE7YXN5bmMgZnVuY3Rpb24gZmEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJibXAtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIE9BPWZhO2FzeW5jIGZ1bmN0aW9uIGNhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iYm1wLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBVQT1jYTthc3luYyBmdW5jdGlvbiBkYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImhkZjUtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIFNBPWRhO2FzeW5jIGZ1bmN0aW9uIEJhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iaGRmNS13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgV0E9QmE7YXN5bmMgZnVuY3Rpb24gQ2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJtaW5jLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBOQT1DYTthc3luYyBmdW5jdGlvbiB5YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1pbmMtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIFBBPXlhO2FzeW5jIGZ1bmN0aW9uIEVhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0ibXJjLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciB4QT1FYTthc3luYyBmdW5jdGlvbiBRYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49Im1yYy13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgR0E9UWE7YXN5bmMgZnVuY3Rpb24gaGEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJsc20tcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIFRBPWhhO2FzeW5jIGZ1bmN0aW9uIHdhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0ibHNtLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBKQT13YTthc3luYyBmdW5jdGlvbiBSYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Im1naC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgTEE9UmE7YXN5bmMgZnVuY3Rpb24gYmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJtZ2gtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIE1BPWJhO2FzeW5jIGZ1bmN0aW9uIGthKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0iYmlvLXJhZC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgSEE9a2E7YXN5bmMgZnVuY3Rpb24gRGEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJiaW8tcmFkLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBZQT1EYTthc3luYyBmdW5jdGlvbiBGYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImdpcGwtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHFBPUZhO2FzeW5jIGZ1bmN0aW9uIE9hKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iZ2lwbC13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgdkE9T2E7YXN5bmMgZnVuY3Rpb24gVWEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJnZS1hZHctcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIEtBPVVhO2FzeW5jIGZ1bmN0aW9uIFNhKGUsQSx0LHI9e30pe2xldCBhPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTp7cGF0aDp0LGRhdGE6bmV3IFVpbnQ4QXJyYXl9fV0sbz1be3R5cGU6bS5JbWFnZSxkYXRhOkF9XSxpPVtdLGw9IjAiO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPXQ7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2Ygci5pbmZvcm1hdGlvbk9ubHk8InUiJiZyLmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKSx0eXBlb2Ygci51c2VDb21wcmVzc2lvbjwidSImJnIudXNlQ29tcHJlc3Npb24mJmkucHVzaCgiLS11c2UtY29tcHJlc3Npb24iKTtsZXQgbj0iZ2UtYWR3LXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBqQT1TYTthc3luYyBmdW5jdGlvbiBXYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49ImdlNC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgX0E9V2E7YXN5bmMgZnVuY3Rpb24gTmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJnZTQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIHpBPU5hO2FzeW5jIGZ1bmN0aW9uIFBhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0iZ2U1LXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBWQT1QYTthc3luYyBmdW5jdGlvbiB4YShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49ImdlNS13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgWkE9eGE7YXN5bmMgZnVuY3Rpb24gR2EoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJnZGNtLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBYQT1HYTthc3luYyBmdW5jdGlvbiBUYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49ImdkY20td3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyICRBPVRhO2FzeW5jIGZ1bmN0aW9uIEphKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0ic2NhbmNvLXJlYWQtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxyLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkUmVhZDpJWzBdPy5kYXRhLGltYWdlOklbMV0/LmRhdGF9fXZhciBldD1KYTthc3luYyBmdW5jdGlvbiBMYShlLEEsdCxyPXt9KXtsZXQgYT1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6e3BhdGg6dCxkYXRhOm5ldyBVaW50OEFycmF5fX1dLG89W3t0eXBlOm0uSW1hZ2UsZGF0YTpBfV0saT1bXSxsPSIwIjtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz10O2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHIuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmci5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5IiksdHlwZW9mIHIudXNlQ29tcHJlc3Npb248InUiJiZyLnVzZUNvbXByZXNzaW9uJiZpLnB1c2goIi0tdXNlLWNvbXByZXNzaW9uIik7bGV0IG49InNjYW5jby13cml0ZS1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLGEsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRXcml0ZTpJWzBdPy5kYXRhLHNlcmlhbGl6ZWRJbWFnZTpJWzFdPy5kYXRhfX12YXIgQXQ9TGE7YXN5bmMgZnVuY3Rpb24gTWEoZSxBLHQ9e30pe2xldCByPVt7dHlwZTptLkpzb25Db21wYXRpYmxlfSx7dHlwZTptLkltYWdlfV0sYT1BO2lmKEEgaW5zdGFuY2VvZiBGaWxlKXtsZXQgRT1hd2FpdCBBLmFycmF5QnVmZmVyKCk7YT17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShFKX19bGV0IG89W3t0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOmF9XSxpPVtdLGw9YS5wYXRoO2kucHVzaChsKTtsZXQgZj0iMCI7aS5wdXNoKGYpO2xldCBnPSIxIjtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiB0LmluZm9ybWF0aW9uT25seTwidSImJnQuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpO2xldCBuPSJmZGYtcmVhZC1pbWFnZSIse3dlYldvcmtlcjp1LHJldHVyblZhbHVlOnAsc3RkZXJyOnMsb3V0cHV0czpJfT1hd2FpdCBCKGUsbixpLHIsbyx7cGlwZWxpbmVCYXNlVXJsOkMoKSxwaXBlbGluZVdvcmtlclVybDp5KCl9KTtpZihwIT09MCYmcyE9PSIiKXRocm93IG5ldyBFcnJvcihzKTtyZXR1cm57d2ViV29ya2VyOnUsY291bGRSZWFkOklbMF0/LmRhdGEsaW1hZ2U6SVsxXT8uZGF0YX19dmFyIHR0PU1hO2FzeW5jIGZ1bmN0aW9uIEhhKGUsQSx0PXt9KXtsZXQgcj1be3R5cGU6bS5Kc29uQ29tcGF0aWJsZX0se3R5cGU6bS5JbWFnZX1dLGE9QTtpZihBIGluc3RhbmNlb2YgRmlsZSl7bGV0IEU9YXdhaXQgQS5hcnJheUJ1ZmZlcigpO2E9e3BhdGg6QS5uYW1lLGRhdGE6bmV3IFVpbnQ4QXJyYXkoRSl9fWxldCBvPVt7dHlwZTptLkJpbmFyeUZpbGUsZGF0YTphfV0saT1bXSxsPWEucGF0aDtpLnB1c2gobCk7bGV0IGY9IjAiO2kucHVzaChmKTtsZXQgZz0iMSI7aS5wdXNoKGcpLGkucHVzaCgiLS1tZW1vcnktaW8iKSx0eXBlb2YgdC5pbmZvcm1hdGlvbk9ubHk8InUiJiZ0LmluZm9ybWF0aW9uT25seSYmaS5wdXNoKCItLWluZm9ybWF0aW9uLW9ubHkiKTtsZXQgbj0id2FzbS1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgcnQ9SGE7YXN5bmMgZnVuY3Rpb24gWWEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ3YXNtLXdyaXRlLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGksYSxvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOklbMF0/LmRhdGEsc2VyaWFsaXplZEltYWdlOklbMV0/LmRhdGF9fXZhciBpdD1ZYTthc3luYyBmdW5jdGlvbiBxYShlLEEsdD17fSl7bGV0IHI9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uSW1hZ2V9XSxhPUE7aWYoQSBpbnN0YW5jZW9mIEZpbGUpe2xldCBFPWF3YWl0IEEuYXJyYXlCdWZmZXIoKTthPXtwYXRoOkEubmFtZSxkYXRhOm5ldyBVaW50OEFycmF5KEUpfX1sZXQgbz1be3R5cGU6bS5CaW5hcnlGaWxlLGRhdGE6YX1dLGk9W10sbD1hLnBhdGg7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9IjEiO2kucHVzaChnKSxpLnB1c2goIi0tbWVtb3J5LWlvIiksdHlwZW9mIHQuaW5mb3JtYXRpb25Pbmx5PCJ1IiYmdC5pbmZvcm1hdGlvbk9ubHkmJmkucHVzaCgiLS1pbmZvcm1hdGlvbi1vbmx5Iik7bGV0IG49Indhc20tenN0ZC1yZWFkLWltYWdlIix7d2ViV29ya2VyOnUscmV0dXJuVmFsdWU6cCxzdGRlcnI6cyxvdXRwdXRzOkl9PWF3YWl0IEIoZSxuLGkscixvLHtwaXBlbGluZUJhc2VVcmw6QygpLHBpcGVsaW5lV29ya2VyVXJsOnkoKX0pO2lmKHAhPT0wJiZzIT09IiIpdGhyb3cgbmV3IEVycm9yKHMpO3JldHVybnt3ZWJXb3JrZXI6dSxjb3VsZFJlYWQ6SVswXT8uZGF0YSxpbWFnZTpJWzFdPy5kYXRhfX12YXIgYXQ9cWE7YXN5bmMgZnVuY3Rpb24gdmEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJ3YXNtLXpzdGQtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIG90PXZhO3ZhciBLYT1uZXcgTWFwKFtbInBuZyIsW2NBLGRBXV0sWyJtZXRhIixbQkEsQ0FdXSxbInRpZmYiLFt5QSxFQV1dLFsibmlmdGkiLFtRQSxoQV1dLFsianBlZyIsW3dBLFJBXV0sWyJucnJkIixbYkEsa0FdXSxbInZ0ayIsW0RBLEZBXV0sWyJibXAiLFtPQSxVQV1dLFsiaGRmNSIsW1NBLFdBXV0sWyJtaW5jIixbTkEsUEFdXSxbIm1yYyIsW3hBLEdBXV0sWyJsc20iLFtUQSxKQV1dLFsibWdoIixbTEEsTUFdXSxbImJpb1JhZCIsW0hBLFlBXV0sWyJnaXBsIixbcUEsdkFdXSxbImdlQWR3IixbS0EsakFdXSxbImdlNCIsW19BLHpBXV0sWyJnZTUiLFtWQSxaQV1dLFsiZ2RjbSIsW1hBLCRBXV0sWyJzY2FuY28iLFtldCxBdF1dLFsiZmRmIixbdHQsbnVsbF1dLFsid2FzbSIsW3J0LGl0XV0sWyJ3YXNtWnN0ZCIsW2F0LG90XV1dKSx0ZT1LYTthc3luYyBmdW5jdGlvbiBqYShlLEEsdD17fSl7bGV0IHI9QS50eXBlPz8iIixhPUEubmFtZT8/QS5wYXRoPz8iZmlsZU5hbWUiLG89bWUoYSkudG9Mb3dlckNhc2UoKSxpPWUsbD1BO2lmKEEgaW5zdGFuY2VvZiBCbG9iKXtsZXQgST1hd2FpdCBBLmFycmF5QnVmZmVyKCk7bD17cGF0aDpBLm5hbWUsZGF0YTpuZXcgVWludDhBcnJheShJKX19bGV0IGY9bnVsbDtpZihyJiZlZS5oYXMocikpZj1lZS5nZXQocik7ZWxzZSBpZihBZS5oYXMobykpZj1BZS5nZXQobyk7ZWxzZSBmb3IobGV0IEkgb2YgdGUudmFsdWVzKCkpaWYoSVswXSE9PW51bGwpe2xldHt3ZWJXb3JrZXI6ZCxjb3VsZFJlYWQ6RSxpbWFnZTpSfT1hd2FpdCBJWzBdKGkse3BhdGg6bC5wYXRoLGRhdGE6bC5kYXRhLnNsaWNlKCl9LHtpbmZvcm1hdGlvbk9ubHk6dC5pbmZvcm1hdGlvbk9ubHl9KTtpZihpPWQsRSlyZXR1cm4gdHlwZW9mIHQ8InUiJiYoUj1UKFIsdCkpLHt3ZWJXb3JrZXI6aSxpbWFnZTpSfX1pZighZil0aHJvdyBFcnJvcigiQ291bGQgbm90IGZpbmQgSU8gZm9yOiAiK2EpO2xldCBuPXRlLmdldChmKVswXSx7d2ViV29ya2VyOnUsY291bGRSZWFkOnAsaW1hZ2U6c309YXdhaXQgbihpLGwse2luZm9ybWF0aW9uT25seTp0LmluZm9ybWF0aW9uT25seX0pO2lmKGk9dSwhcCl0aHJvdyBFcnJvcigiQ291bGQgbm90IHJlYWQ6ICIrYSk7cmV0dXJuIHR5cGVvZiB0PCJ1IiYmKHM9VChzLHQpKSx7d2ViV29ya2VyOmksaW1hZ2U6c319dmFyIG50PWphO3ZhciBfYT10eXBlb2YgZ2xvYmFsVGhpcy5uYXZpZ2F0b3I/LmhhcmR3YXJlQ29uY3VycmVuY3k9PSJudW1iZXIiP2dsb2JhbFRoaXMubmF2aWdhdG9yLmhhcmR3YXJlQ29uY3VycmVuY3k6Nixtcj1uZXcgSmUoX2EsbnQpO2FzeW5jIGZ1bmN0aW9uIHphKGUsQSl7bGV0IHQ9MSxyPTAsYT0hMTt0eXBlb2YgQT09Im9iamVjdCImJih0eXBlb2YgQS56U3BhY2luZzwidSImJih0PUEuelNwYWNpbmcpLHR5cGVvZiBBLnpPcmlnaW48InUiJiYocj1BLnpPcmlnaW4pLHR5cGVvZiBBLnNvcnRlZFNlcmllczwidSImJihhPUEuc29ydGVkU2VyaWVzKSk7bGV0IG89QXJyYXkuZnJvbShlLGFzeW5jIGZ1bmN0aW9uKHUpe3JldHVybiBhd2FpdCB1LmFycmF5QnVmZmVyKCkudGhlbihmdW5jdGlvbihwKXtyZXR1cm57bmFtZTp1Lm5hbWUsdHlwZTp1LnR5cGUsZGF0YTpwfX0pfSksaT1hd2FpdCBQcm9taXNlLmFsbChvKTthfHxpLnNvcnQoKHUscCk9PnUubmFtZTxwLm5hbWU/LTE6dS5uYW1lPnAubmFtZT8xOjApO2xldCBsPVtdO2ZvcihsZXQgdT0wO3U8aS5sZW5ndGg7dSsrKWwucHVzaChbaVt1XS5kYXRhLGlbdV0ubmFtZV0pO2xldCBnPShhd2FpdCBtci5ydW5UYXNrcyhsKS5wcm9taXNlKS5tYXAodT0+e2xldCBwPXUuaW1hZ2U7cmV0dXJuIHAuaW1hZ2VUeXBlLmRpbWVuc2lvbj0zLHAuc2l6ZS5wdXNoKDEpLHAuc3BhY2luZy5wdXNoKHQpLHAub3JpZ2luLnB1c2gocikscC5kaXJlY3Rpb249bmV3IEZsb2F0NjRBcnJheSg5KSxwLmRpcmVjdGlvbi5maWxsKDApLHAuZGlyZWN0aW9uWzBdPTEscC5kaXJlY3Rpb25bNF09MSxwLmRpcmVjdGlvbls4XT0xLHB9KSxuPUdlKGcpO3JldHVybiB0eXBlb2YgQT09Im9iamVjdCImJih0eXBlb2YgQS5jb21wb25lbnRUeXBlPCJ1Inx8dHlwZW9mIEEucGl4ZWxUeXBlPCJ1IikmJihuPVQobixBKSkse2ltYWdlOm4sd2ViV29ya2VyUG9vbDptcn19dmFyIFZhPXphO2FzeW5jIGZ1bmN0aW9uIFphKGUsQSx0LHI9e30pe2xldCBhPUE7KHR5cGVvZiByLmNvbXBvbmVudFR5cGU8InUifHx0eXBlb2Ygci5waXhlbFR5cGU8InUiKSYmKGE9VChBLHIpKTtsZXQgbz1yLm1pbWVUeXBlLGk9bWUodCkudG9Mb3dlckNhc2UoKSxsPWUsZj1udWxsO2lmKHR5cGVvZiBvPCJ1IiYmZWUuaGFzKG8pKWY9ZWUuZ2V0KG8pO2Vsc2UgaWYoQWUuaGFzKGkpKWY9QWUuZ2V0KGkpO2Vsc2UgZm9yKGxldCBkIG9mIHRlLnZhbHVlcygpKWlmKGRbMV0hPT1udWxsKXtsZXR7d2ViV29ya2VyOkUsY291bGRXcml0ZTpSLHNlcmlhbGl6ZWRJbWFnZTp3fT1hd2FpdCBkWzFdKGwseGUoYSksdCxyKTtpZihsPUUsUilyZXR1cm57d2ViV29ya2VyOmwsc2VyaWFsaXplZEltYWdlOnd9fWlmKCFmKXRocm93IEVycm9yKCJDb3VsZCBub3QgZmluZCBJTyBmb3I6ICIrdCk7bGV0IG49dGUuZ2V0KGYpWzFdLHt3ZWJXb3JrZXI6dSxjb3VsZFdyaXRlOnAsc2VyaWFsaXplZEltYWdlOnN9PWF3YWl0IG4obCxhLHQscik7aWYobD11LCFwKXRocm93IEVycm9yKCJDb3VsZCBub3Qgd3JpdGU6ICIrdCk7cmV0dXJue3dlYldvcmtlcjpsLHNlcmlhbGl6ZWRJbWFnZTpzfX12YXIgWGE9WmE7YXN5bmMgZnVuY3Rpb24gJGEoZSxBLHQscj17fSl7bGV0IGE9W3t0eXBlOm0uSnNvbkNvbXBhdGlibGV9LHt0eXBlOm0uQmluYXJ5RmlsZSxkYXRhOntwYXRoOnQsZGF0YTpuZXcgVWludDhBcnJheX19XSxvPVt7dHlwZTptLkltYWdlLGRhdGE6QX1dLGk9W10sbD0iMCI7aS5wdXNoKGwpO2xldCBmPSIwIjtpLnB1c2goZik7bGV0IGc9dDtpLnB1c2goZyksaS5wdXNoKCItLW1lbW9yeS1pbyIpLHR5cGVvZiByLmluZm9ybWF0aW9uT25seTwidSImJnIuaW5mb3JtYXRpb25Pbmx5JiZpLnB1c2goIi0taW5mb3JtYXRpb24tb25seSIpLHR5cGVvZiByLnVzZUNvbXByZXNzaW9uPCJ1IiYmci51c2VDb21wcmVzc2lvbiYmaS5wdXNoKCItLXVzZS1jb21wcmVzc2lvbiIpO2xldCBuPSJmZGYtd3JpdGUtaW1hZ2UiLHt3ZWJXb3JrZXI6dSxyZXR1cm5WYWx1ZTpwLHN0ZGVycjpzLG91dHB1dHM6SX09YXdhaXQgQihlLG4saSxhLG8se3BpcGVsaW5lQmFzZVVybDpDKCkscGlwZWxpbmVXb3JrZXJVcmw6eSgpfSk7aWYocCE9PTAmJnMhPT0iIil0aHJvdyBuZXcgRXJyb3Iocyk7cmV0dXJue3dlYldvcmtlcjp1LGNvdWxkV3JpdGU6SVswXT8uZGF0YSxzZXJpYWxpemVkSW1hZ2U6SVsxXT8uZGF0YX19dmFyIGVvPSRhO3ZhciB1cj0nZGF0YTp0ZXh0L2phdmFzY3JpcHQ7Y2hhcnNldD11dGYtOCx2YXIgY2U9U3ltYm9sKCJDb21saW5rLnByb3h5IiksQ3Q9U3ltYm9sKCJDb21saW5rLmVuZHBvaW50IiksQnQ9U3ltYm9sKCJDb21saW5rLnJlbGVhc2VQcm94eSIpLE1BPVN5bWJvbCgiQ29tbGluay5maW5hbGl6ZXIiKSxzQT1TeW1ib2woIkNvbWxpbmsudGhyb3duIiksZmU9QT0+dHlwZW9mIEE9PSJvYmplY3QiJiZBIT09bnVsbHx8dHlwZW9mIEE9PSJmdW5jdGlvbiIsUXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmQVtjZV0sc2VyaWFsaXplKEEpe2xldHtwb3J0MTplLHBvcnQyOnR9PW5ldyBNZXNzYWdlQ2hhbm5lbDtyZXR1cm4gRUEoQSxlKSxbdCxbdF1dfSxkZXNlcmlhbGl6ZShBKXtyZXR1cm4gQS5zdGFydCgpLGx0KEEpfX0sRXQ9e2NhbkhhbmRsZTpBPT5mZShBKSYmc0EgaW4gQSxzZXJpYWxpemUoe3ZhbHVlOkF9KXtsZXQgZTtyZXR1cm4gQSBpbnN0YW5jZW9mIEVycm9yP2U9e2lzRXJyb3I6ITAsdmFsdWU6e21lc3NhZ2U6QS5tZXNzYWdlLG5hbWU6QS5uYW1lLHN0YWNrOkEuc3RhY2t9fTplPXtpc0Vycm9yOiExLHZhbHVlOkF9LFtlLFtdXX0sZGVzZXJpYWxpemUoQSl7dGhyb3cgQS5pc0Vycm9yP09iamVjdC5hc3NpZ24obmV3IEVycm9yKEEudmFsdWUubWVzc2FnZSksQS52YWx1ZSk6QS52YWx1ZX19LGxlPW5ldyBNYXAoW1sicHJveHkiLFF0XSxbInRocm93IixFdF1dKTtmdW5jdGlvbiBjdChBLGUpe2ZvcihsZXQgdCBvZiBBKWlmKGU9PT10fHx0PT09IioifHx0IGluc3RhbmNlb2YgUmVnRXhwJiZ0LnRlc3QoZSkpcmV0dXJuITA7cmV0dXJuITF9ZnVuY3Rpb24gRUEoQSxlPWdsb2JhbFRoaXMsdD1bIioiXSl7ZS5hZGRFdmVudExpc3RlbmVyKCJtZXNzYWdlIixmdW5jdGlvbiBJKHIpe2lmKCFyfHwhci5kYXRhKXJldHVybjtpZighY3QodCxyLm9yaWdpbikpe2NvbnNvbGUud2FybihgSW52YWxpZCBvcmlnaW4gXCcke3Iub3JpZ2lufVwnIGZvciBjb21saW5rIHByb3h5YCk7cmV0dXJufWxldHtpZDppLHR5cGU6ZyxwYXRoOm59PU9iamVjdC5hc3NpZ24oe3BhdGg6W119LHIuZGF0YSksRT0oci5kYXRhLmFyZ3VtZW50TGlzdHx8W10pLm1hcChxKSxvO3RyeXtsZXQgQj1uLnNsaWNlKDAsLTEpLnJlZHVjZSgoYSxDKT0+YVtDXSxBKSxjPW4ucmVkdWNlKChhLEMpPT5hW0NdLEEpO3N3aXRjaChnKXtjYXNlIkdFVCI6bz1jO2JyZWFrO2Nhc2UiU0VUIjpCW24uc2xpY2UoLTEpWzBdXT1xKHIuZGF0YS52YWx1ZSksbz0hMDticmVhaztjYXNlIkFQUExZIjpvPWMuYXBwbHkoQixFKTticmVhaztjYXNlIkNPTlNUUlVDVCI6e2xldCBhPW5ldyBjKC4uLkUpO289bXQoYSl9YnJlYWs7Y2FzZSJFTkRQT0lOVCI6e2xldHtwb3J0MTphLHBvcnQyOkN9PW5ldyBNZXNzYWdlQ2hhbm5lbDtFQShBLEMpLG89SEEoYSxbYV0pfWJyZWFrO2Nhc2UiUkVMRUFTRSI6bz12b2lkIDA7YnJlYWs7ZGVmYXVsdDpyZXR1cm59fWNhdGNoKEIpe289e3ZhbHVlOkIsW3NBXTowfX1Qcm9taXNlLnJlc29sdmUobykuY2F0Y2goQj0+KHt2YWx1ZTpCLFtzQV06MH0pKS50aGVuKEI9PntsZXRbYyxhXT1RQShCKTtlLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oT2JqZWN0LmFzc2lnbih7fSxjKSx7aWQ6aX0pLGEpLGc9PT0iUkVMRUFTRSImJihlLnJlbW92ZUV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLEkpLHVlKGUpLE1BIGluIEEmJnR5cGVvZiBBW01BXT09ImZ1bmN0aW9uIiYmQVtNQV0oKSl9KS5jYXRjaChCPT57bGV0W2MsYV09UUEoe3ZhbHVlOm5ldyBUeXBlRXJyb3IoIlVuc2VyaWFsaXphYmxlIHJldHVybiB2YWx1ZSIpLFtzQV06MH0pO2UucG9zdE1lc3NhZ2UoT2JqZWN0LmFzc2lnbihPYmplY3QuYXNzaWduKHt9LGMpLHtpZDppfSksYSl9KX0pLGUuc3RhcnQmJmUuc3RhcnQoKX1mdW5jdGlvbiBmdChBKXtyZXR1cm4gQS5jb25zdHJ1Y3Rvci5uYW1lPT09Ik1lc3NhZ2VQb3J0In1mdW5jdGlvbiB1ZShBKXtmdChBKSYmQS5jbG9zZSgpfWZ1bmN0aW9uIGx0KEEsZSl7cmV0dXJuIGJBKEEsW10sZSl9ZnVuY3Rpb24gYUEoQSl7aWYoQSl0aHJvdyBuZXcgRXJyb3IoIlByb3h5IGhhcyBiZWVuIHJlbGVhc2VkIGFuZCBpcyBub3QgdXNlYWJsZSIpfWZ1bmN0aW9uIGhlKEEpe3JldHVybiB4KEEse3R5cGU6IlJFTEVBU0UifSkudGhlbigoKT0+e3VlKEEpfSl9dmFyIENBPW5ldyBXZWFrTWFwLEJBPSJGaW5hbGl6YXRpb25SZWdpc3RyeSJpbiBnbG9iYWxUaGlzJiZuZXcgRmluYWxpemF0aW9uUmVnaXN0cnkoQT0+e2xldCBlPShDQS5nZXQoQSl8fDApLTE7Q0Euc2V0KEEsZSksZT09PTAmJmhlKEEpfSk7ZnVuY3Rpb24gdXQoQSxlKXtsZXQgdD0oQ0EuZ2V0KGUpfHwwKSsxO0NBLnNldChlLHQpLEJBJiZCQS5yZWdpc3RlcihBLGUsQSl9ZnVuY3Rpb24gaHQoQSl7QkEmJkJBLnVucmVnaXN0ZXIoQSl9ZnVuY3Rpb24gYkEoQSxlPVtdLHQ9ZnVuY3Rpb24oKXt9KXtsZXQgST0hMSxyPW5ldyBQcm94eSh0LHtnZXQoaSxnKXtpZihhQShJKSxnPT09QnQpcmV0dXJuKCk9PntodChyKSxoZShBKSxJPSEwfTtpZihnPT09InRoZW4iKXtpZihlLmxlbmd0aD09PTApcmV0dXJue3RoZW46KCk9PnJ9O2xldCBuPXgoQSx7dHlwZToiR0VUIixwYXRoOmUubWFwKEU9PkUudG9TdHJpbmcoKSl9KS50aGVuKHEpO3JldHVybiBuLnRoZW4uYmluZChuKX1yZXR1cm4gYkEoQSxbLi4uZSxnXSl9LHNldChpLGcsbil7YUEoSSk7bGV0W0Usb109UUEobik7cmV0dXJuIHgoQSx7dHlwZToiU0VUIixwYXRoOlsuLi5lLGddLm1hcChCPT5CLnRvU3RyaW5nKCkpLHZhbHVlOkV9LG8pLnRoZW4ocSl9LGFwcGx5KGksZyxuKXthQShJKTtsZXQgRT1lW2UubGVuZ3RoLTFdO2lmKEU9PT1DdClyZXR1cm4geChBLHt0eXBlOiJFTkRQT0lOVCJ9KS50aGVuKHEpO2lmKEU9PT0iYmluZCIpcmV0dXJuIGJBKEEsZS5zbGljZSgwLC0xKSk7bGV0W28sQl09RWUobik7cmV0dXJuIHgoQSx7dHlwZToiQVBQTFkiLHBhdGg6ZS5tYXAoYz0+Yy50b1N0cmluZygpKSxhcmd1bWVudExpc3Q6b30sQikudGhlbihxKX0sY29uc3RydWN0KGksZyl7YUEoSSk7bGV0W24sRV09RWUoZyk7cmV0dXJuIHgoQSx7dHlwZToiQ09OU1RSVUNUIixwYXRoOmUubWFwKG89Pm8udG9TdHJpbmcoKSksYXJndW1lbnRMaXN0Om59LEUpLnRoZW4ocSl9fSk7cmV0dXJuIHV0KHIsQSkscn1mdW5jdGlvbiBkdChBKXtyZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShbXSxBKX1mdW5jdGlvbiBFZShBKXtsZXQgZT1BLm1hcChRQSk7cmV0dXJuW2UubWFwKHQ9PnRbMF0pLGR0KGUubWFwKHQ9PnRbMV0pKV19dmFyIGRlPW5ldyBXZWFrTWFwO2Z1bmN0aW9uIEhBKEEsZSl7cmV0dXJuIGRlLnNldChBLGUpLEF9ZnVuY3Rpb24gbXQoQSl7cmV0dXJuIE9iamVjdC5hc3NpZ24oQSx7W2NlXTohMH0pfWZ1bmN0aW9uIFFBKEEpe2ZvcihsZXRbZSx0XW9mIGxlKWlmKHQuY2FuSGFuZGxlKEEpKXtsZXRbSSxyXT10LnNlcmlhbGl6ZShBKTtyZXR1cm5be3R5cGU6IkhBTkRMRVIiLG5hbWU6ZSx2YWx1ZTpJfSxyXX1yZXR1cm5be3R5cGU6IlJBVyIsdmFsdWU6QX0sZGUuZ2V0KEEpfHxbXV19ZnVuY3Rpb24gcShBKXtzd2l0Y2goQS50eXBlKXtjYXNlIkhBTkRMRVIiOnJldHVybiBsZS5nZXQoQS5uYW1lKS5kZXNlcmlhbGl6ZShBLnZhbHVlKTtjYXNlIlJBVyI6cmV0dXJuIEEudmFsdWV9fWZ1bmN0aW9uIHgoQSxlLHQpe3JldHVybiBuZXcgUHJvbWlzZShJPT57bGV0IHI9RHQoKTtBLmFkZEV2ZW50TGlzdGVuZXIoIm1lc3NhZ2UiLGZ1bmN0aW9uIGkoZyl7IWcuZGF0YXx8IWcuZGF0YS5pZHx8Zy5kYXRhLmlkIT09cnx8KEEucmVtb3ZlRXZlbnRMaXN0ZW5lcigibWVzc2FnZSIsaSksSShnLmRhdGEpKX0pLEEuc3RhcnQmJkEuc3RhcnQoKSxBLnBvc3RNZXNzYWdlKE9iamVjdC5hc3NpZ24oe2lkOnJ9LGUpLHQpfSl9ZnVuY3Rpb24gRHQoKXtyZXR1cm4gbmV3IEFycmF5KDQpLmZpbGwoMCkubWFwKCgpPT5NYXRoLmZsb29yKE1hdGgucmFuZG9tKCkqTnVtYmVyLk1BWF9TQUZFX0lOVEVHRVIpLnRvU3RyaW5nKDE2KSkuam9pbigiLSIpfWZ1bmN0aW9uIFgoQSxlKXtyZXR1cm4gZnVuY3Rpb24oKXtyZXR1cm4gQS5hcHBseShlLGFyZ3VtZW50cyl9fXZhcnt0b1N0cmluZzp5dH09T2JqZWN0LnByb3RvdHlwZSx7Z2V0UHJvdG90eXBlT2Y6VEF9PU9iamVjdCxmQT0oQT0+ZT0+e2xldCB0PXl0LmNhbGwoZSk7cmV0dXJuIEFbdF18fChBW3RdPXQuc2xpY2UoOCwtMSkudG9Mb3dlckNhc2UoKSl9KShPYmplY3QuY3JlYXRlKG51bGwpKSxVPUE9PihBPUEudG9Mb3dlckNhc2UoKSxlPT5mQShlKT09PUEpLGxBPUE9PmU9PnR5cGVvZiBlPT09QSx7aXNBcnJheTpQfT1BcnJheSx2PWxBKCJ1bmRlZmluZWQiKTtmdW5jdGlvbiB3dChBKXtyZXR1cm4gQSE9PW51bGwmJiF2KEEpJiZBLmNvbnN0cnVjdG9yIT09bnVsbCYmIXYoQS5jb25zdHJ1Y3RvcikmJlIoQS5jb25zdHJ1Y3Rvci5pc0J1ZmZlcikmJkEuY29uc3RydWN0b3IuaXNCdWZmZXIoQSl9dmFyIHdlPVUoIkFycmF5QnVmZmVyIik7ZnVuY3Rpb24gcHQoQSl7bGV0IGU7cmV0dXJuIHR5cGVvZiBBcnJheUJ1ZmZlcjwidSImJkFycmF5QnVmZmVyLmlzVmlldz9lPUFycmF5QnVmZmVyLmlzVmlldyhBKTplPUEmJkEuYnVmZmVyJiZ3ZShBLmJ1ZmZlciksZX12YXIgRnQ9bEEoInN0cmluZyIpLFI9bEEoImZ1bmN0aW9uIikscGU9bEEoIm51bWJlciIpLHVBPUE9PkEhPT1udWxsJiZ0eXBlb2YgQT09Im9iamVjdCIsU3Q9QT0+QT09PSEwfHxBPT09ITEsY0E9QT0+e2lmKGZBKEEpIT09Im9iamVjdCIpcmV0dXJuITE7bGV0IGU9VEEoQSk7cmV0dXJuKGU9PT1udWxsfHxlPT09T2JqZWN0LnByb3RvdHlwZXx8T2JqZWN0LmdldFByb3RvdHlwZU9mKGUpPT09bnVsbCkmJiEoU3ltYm9sLnRvU3RyaW5nVGFnIGluIEEpJiYhKFN5bWJvbC5pdGVyYXRvciBpbiBBKX0sTnQ9VSgiRGF0ZSIpLFJ0PVUoIkZpbGUiKSxHdD1VKCJCbG9iIiksVXQ9VSgiRmlsZUxpc3QiKSxrdD1BPT51QShBKSYmUihBLnBpcGUpLEx0PUE9PntsZXQgZTtyZXR1cm4gQSYmKHR5cGVvZiBGb3JtRGF0YT09ImZ1bmN0aW9uIiYmQSBpbnN0YW5jZW9mIEZvcm1EYXRhfHxSKEEuYXBwZW5kKSYmKChlPWZBKEEpKT09PSJmb3JtZGF0YSJ8fGU9PT0ib2JqZWN0IiYmUihBLnRvU3RyaW5nKSYmQS50b1N0cmluZygpPT09IltvYmplY3QgRm9ybURhdGFdIikpfSxPdD1VKCJVUkxTZWFyY2hQYXJhbXMiKSxKdD1BPT5BLnRyaW0/QS50cmltKCk6QS5yZXBsYWNlKC9eW1xcc1xcdUZFRkZcXHhBMF0rfFtcXHNcXHVGRUZGXFx4QTBdKyQvZywiIik7ZnVuY3Rpb24gJChBLGUse2FsbE93bktleXM6dD0hMX09e30pe2lmKEE9PT1udWxsfHx0eXBlb2YgQT4idSIpcmV0dXJuO2xldCBJLHI7aWYodHlwZW9mIEEhPSJvYmplY3QiJiYoQT1bQV0pLFAoQSkpZm9yKEk9MCxyPUEubGVuZ3RoO0k8cjtJKyspZS5jYWxsKG51bGwsQVtJXSxJLEEpO2Vsc2V7bGV0IGk9dD9PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKTpPYmplY3Qua2V5cyhBKSxnPWkubGVuZ3RoLG47Zm9yKEk9MDtJPGc7SSsrKW49aVtJXSxlLmNhbGwobnVsbCxBW25dLG4sQSl9fWZ1bmN0aW9uIEZlKEEsZSl7ZT1lLnRvTG93ZXJDYXNlKCk7bGV0IHQ9T2JqZWN0LmtleXMoQSksST10Lmxlbmd0aCxyO2Zvcig7SS0tID4wOylpZihyPXRbSV0sZT09PXIudG9Mb3dlckNhc2UoKSlyZXR1cm4gcjtyZXR1cm4gbnVsbH12YXIgU2U9KCgpPT50eXBlb2YgZ2xvYmFsVGhpczwidSI/Z2xvYmFsVGhpczp0eXBlb2Ygc2VsZjwidSI/c2VsZjp0eXBlb2Ygd2luZG93PCJ1Ij93aW5kb3c6Z2xvYmFsKSgpLE5lPUE9PiF2KEEpJiZBIT09U2U7ZnVuY3Rpb24gcUEoKXtsZXR7Y2FzZWxlc3M6QX09TmUodGhpcykmJnRoaXN8fHt9LGU9e30sdD0oSSxyKT0+e2xldCBpPUEmJkZlKGUscil8fHI7Y0EoZVtpXSkmJmNBKEkpP2VbaV09cUEoZVtpXSxJKTpjQShJKT9lW2ldPXFBKHt9LEkpOlAoSSk/ZVtpXT1JLnNsaWNlKCk6ZVtpXT1JfTtmb3IobGV0IEk9MCxyPWFyZ3VtZW50cy5sZW5ndGg7STxyO0krKylhcmd1bWVudHNbSV0mJiQoYXJndW1lbnRzW0ldLHQpO3JldHVybiBlfXZhciBNdD0oQSxlLHQse2FsbE93bktleXM6SX09e30pPT4oJChlLChyLGkpPT57dCYmUihyKT9BW2ldPVgocix0KTpBW2ldPXJ9LHthbGxPd25LZXlzOkl9KSxBKSxidD1BPT4oQS5jaGFyQ29kZUF0KDApPT09NjUyNzkmJihBPUEuc2xpY2UoMSkpLEEpLEh0PShBLGUsdCxJKT0+e0EucHJvdG90eXBlPU9iamVjdC5jcmVhdGUoZS5wcm90b3R5cGUsSSksQS5wcm90b3R5cGUuY29uc3RydWN0b3I9QSxPYmplY3QuZGVmaW5lUHJvcGVydHkoQSwic3VwZXIiLHt2YWx1ZTplLnByb3RvdHlwZX0pLHQmJk9iamVjdC5hc3NpZ24oQS5wcm90b3R5cGUsdCl9LFl0PShBLGUsdCxJKT0+e2xldCByLGksZyxuPXt9O2lmKGU9ZXx8e30sQT09bnVsbClyZXR1cm4gZTtkb3tmb3Iocj1PYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyhBKSxpPXIubGVuZ3RoO2ktLSA+MDspZz1yW2ldLCghSXx8SShnLEEsZSkpJiYhbltnXSYmKGVbZ109QVtnXSxuW2ddPSEwKTtBPXQhPT0hMSYmVEEoQSl9d2hpbGUoQSYmKCF0fHx0KEEsZSkpJiZBIT09T2JqZWN0LnByb3RvdHlwZSk7cmV0dXJuIGV9LHF0PShBLGUsdCk9PntBPVN0cmluZyhBKSwodD09PXZvaWQgMHx8dD5BLmxlbmd0aCkmJih0PUEubGVuZ3RoKSx0LT1lLmxlbmd0aDtsZXQgST1BLmluZGV4T2YoZSx0KTtyZXR1cm4gSSE9PS0xJiZJPT09dH0sVHQ9QT0+e2lmKCFBKXJldHVybiBudWxsO2lmKFAoQSkpcmV0dXJuIEE7bGV0IGU9QS5sZW5ndGg7aWYoIXBlKGUpKXJldHVybiBudWxsO2xldCB0PW5ldyBBcnJheShlKTtmb3IoO2UtLSA+MDspdFtlXT1BW2VdO3JldHVybiB0fSxLdD0oQT0+ZT0+QSYmZSBpbnN0YW5jZW9mIEEpKHR5cGVvZiBVaW50OEFycmF5PCJ1IiYmVEEoVWludDhBcnJheSkpLHh0PShBLGUpPT57bGV0IEk9KEEmJkFbU3ltYm9sLml0ZXJhdG9yXSkuY2FsbChBKSxyO2Zvcig7KHI9SS5uZXh0KCkpJiYhci5kb25lOyl7bGV0IGk9ci52YWx1ZTtlLmNhbGwoQSxpWzBdLGlbMV0pfX0sUHQ9KEEsZSk9PntsZXQgdCxJPVtdO2Zvcig7KHQ9QS5leGVjKGUpKSE9PW51bGw7KUkucHVzaCh0KTtyZXR1cm4gSX0sV3Q9VSgiSFRNTEZvcm1FbGVtZW50IiksanQ9QT0+QS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoL1stX1xcc10oW2EtelxcZF0pKFxcdyopL2csZnVuY3Rpb24odCxJLHIpe3JldHVybiBJLnRvVXBwZXJDYXNlKCkrcn0pLERlPSgoe2hhc093blByb3BlcnR5OkF9KT0+KGUsdCk9PkEuY2FsbChlLHQpKShPYmplY3QucHJvdG90eXBlKSxadD1VKCJSZWdFeHAiKSxSZT0oQSxlKT0+e2xldCB0PU9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzKEEpLEk9e307JCh0LChyLGkpPT57ZShyLGksQSkhPT0hMSYmKElbaV09cil9KSxPYmplY3QuZGVmaW5lUHJvcGVydGllcyhBLEkpfSxfdD1BPT57UmUoQSwoZSx0KT0+e2lmKFIoQSkmJlsiYXJndW1lbnRzIiwiY2FsbGVyIiwiY2FsbGVlIl0uaW5kZXhPZih0KSE9PS0xKXJldHVybiExO2xldCBJPUFbdF07aWYoUihJKSl7aWYoZS5lbnVtZXJhYmxlPSExLCJ3cml0YWJsZSJpbiBlKXtlLndyaXRhYmxlPSExO3JldHVybn1lLnNldHx8KGUuc2V0PSgpPT57dGhyb3cgRXJyb3IoIkNhbiBub3QgcmV3cml0ZSByZWFkLW9ubHkgbWV0aG9kIFwnIit0KyJcJyIpfSl9fSl9LFZ0PShBLGUpPT57bGV0IHQ9e30sST1yPT57ci5mb3JFYWNoKGk9Pnt0W2ldPSEwfSl9O3JldHVybiBQKEEpP0koQSk6SShTdHJpbmcoQSkuc3BsaXQoZSkpLHR9LHp0PSgpPT57fSxYdD0oQSxlKT0+KEE9K0EsTnVtYmVyLmlzRmluaXRlKEEpP0E6ZSksWUE9ImFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6Iix5ZT0iMDEyMzQ1Njc4OSIsR2U9e0RJR0lUOnllLEFMUEhBOllBLEFMUEhBX0RJR0lUOllBK1lBLnRvVXBwZXJDYXNlKCkreWV9LHZ0PShBPTE2LGU9R2UuQUxQSEFfRElHSVQpPT57bGV0IHQ9IiIse2xlbmd0aDpJfT1lO2Zvcig7QS0tOyl0Kz1lW01hdGgucmFuZG9tKCkqSXwwXTtyZXR1cm4gdH07ZnVuY3Rpb24gJHQoQSl7cmV0dXJuISEoQSYmUihBLmFwcGVuZCkmJkFbU3ltYm9sLnRvU3RyaW5nVGFnXT09PSJGb3JtRGF0YSImJkFbU3ltYm9sLml0ZXJhdG9yXSl9dmFyIEFJPUE9PntsZXQgZT1uZXcgQXJyYXkoMTApLHQ9KEkscik9PntpZih1QShJKSl7aWYoZS5pbmRleE9mKEkpPj0wKXJldHVybjtpZighKCJ0b0pTT04iaW4gSSkpe2Vbcl09STtsZXQgaT1QKEkpP1tdOnt9O3JldHVybiAkKEksKGcsbik9PntsZXQgRT10KGcscisxKTshdihFKSYmKGlbbl09RSl9KSxlW3JdPXZvaWQgMCxpfX1yZXR1cm4gSX07cmV0dXJuIHQoQSwwKX0sZUk9VSgiQXN5bmNGdW5jdGlvbiIpLHRJPUE9PkEmJih1QShBKXx8UihBKSkmJlIoQS50aGVuKSYmUihBLmNhdGNoKSxzPXtpc0FycmF5OlAsaXNBcnJheUJ1ZmZlcjp3ZSxpc0J1ZmZlcjp3dCxpc0Zvcm1EYXRhOkx0LGlzQXJyYXlCdWZmZXJWaWV3OnB0LGlzU3RyaW5nOkZ0LGlzTnVtYmVyOnBlLGlzQm9vbGVhbjpTdCxpc09iamVjdDp1QSxpc1BsYWluT2JqZWN0OmNBLGlzVW5kZWZpbmVkOnYsaXNEYXRlOk50LGlzRmlsZTpSdCxpc0Jsb2I6R3QsaXNSZWdFeHA6WnQsaXNGdW5jdGlvbjpSLGlzU3RyZWFtOmt0LGlzVVJMU2VhcmNoUGFyYW1zOk90LGlzVHlwZWRBcnJheTpLdCxpc0ZpbGVMaXN0OlV0LGZvckVhY2g6JCxtZXJnZTpxQSxleHRlbmQ6TXQsdHJpbTpKdCxzdHJpcEJPTTpidCxpbmhlcml0czpIdCx0b0ZsYXRPYmplY3Q6WXQsa2luZE9mOmZBLGtpbmRPZlRlc3Q6VSxlbmRzV2l0aDpxdCx0b0FycmF5OlR0LGZvckVhY2hFbnRyeTp4dCxtYXRjaEFsbDpQdCxpc0hUTUxGb3JtOld0LGhhc093blByb3BlcnR5OkRlLGhhc093blByb3A6RGUscmVkdWNlRGVzY3JpcHRvcnM6UmUsZnJlZXplTWV0aG9kczpfdCx0b09iamVjdFNldDpWdCx0b0NhbWVsQ2FzZTpqdCxub29wOnp0LHRvRmluaXRlTnVtYmVyOlh0LGZpbmRLZXk6RmUsZ2xvYmFsOlNlLGlzQ29udGV4dERlZmluZWQ6TmUsQUxQSEFCRVQ6R2UsZ2VuZXJhdGVTdHJpbmc6dnQsaXNTcGVjQ29tcGxpYW50Rm9ybTokdCx0b0pTT05PYmplY3Q6QUksaXNBc3luY0ZuOmVJLGlzVGhlbmFibGU6dEl9O2Z1bmN0aW9uIFcoQSxlLHQsSSxyKXtFcnJvci5jYWxsKHRoaXMpLEVycm9yLmNhcHR1cmVTdGFja1RyYWNlP0Vycm9yLmNhcHR1cmVTdGFja1RyYWNlKHRoaXMsdGhpcy5jb25zdHJ1Y3Rvcik6dGhpcy5zdGFjaz1uZXcgRXJyb3IoKS5zdGFjayx0aGlzLm1lc3NhZ2U9QSx0aGlzLm5hbWU9IkF4aW9zRXJyb3IiLGUmJih0aGlzLmNvZGU9ZSksdCYmKHRoaXMuY29uZmlnPXQpLEkmJih0aGlzLnJlcXVlc3Q9SSksciYmKHRoaXMucmVzcG9uc2U9cil9cy5pbmhlcml0cyhXLEVycm9yLHt0b0pTT046ZnVuY3Rpb24oKXtyZXR1cm57bWVzc2FnZTp0aGlzLm1lc3NhZ2UsbmFtZTp0aGlzLm5hbWUsZGVzY3JpcHRpb246dGhpcy5kZXNjcmlwdGlvbixudW1iZXI6dGhpcy5udW1iZXIsZmlsZU5hbWU6dGhpcy5maWxlTmFtZSxsaW5lTnVtYmVyOnRoaXMubGluZU51bWJlcixjb2x1bW5OdW1iZXI6dGhpcy5jb2x1bW5OdW1iZXIsc3RhY2s6dGhpcy5zdGFjayxjb25maWc6cy50b0pTT05PYmplY3QodGhpcy5jb25maWcpLGNvZGU6dGhpcy5jb2RlLHN0YXR1czp0aGlzLnJlc3BvbnNlJiZ0aGlzLnJlc3BvbnNlLnN0YXR1cz90aGlzLnJlc3BvbnNlLnN0YXR1czpudWxsfX19KTt2YXIgVWU9Vy5wcm90b3R5cGUsa2U9e307WyJFUlJfQkFEX09QVElPTl9WQUxVRSIsIkVSUl9CQURfT1BUSU9OIiwiRUNPTk5BQk9SVEVEIiwiRVRJTUVET1VUIiwiRVJSX05FVFdPUksiLCJFUlJfRlJfVE9PX01BTllfUkVESVJFQ1RTIiwiRVJSX0RFUFJFQ0FURUQiLCJFUlJfQkFEX1JFU1BPTlNFIiwiRVJSX0JBRF9SRVFVRVNUIiwiRVJSX0NBTkNFTEVEIiwiRVJSX05PVF9TVVBQT1JUIiwiRVJSX0lOVkFMSURfVVJMIl0uZm9yRWFjaChBPT57a2VbQV09e3ZhbHVlOkF9fSk7T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoVyxrZSk7T2JqZWN0LmRlZmluZVByb3BlcnR5KFVlLCJpc0F4aW9zRXJyb3IiLHt2YWx1ZTohMH0pO1cuZnJvbT0oQSxlLHQsSSxyLGkpPT57bGV0IGc9T2JqZWN0LmNyZWF0ZShVZSk7cmV0dXJuIHMudG9GbGF0T2JqZWN0KEEsZyxmdW5jdGlvbihFKXtyZXR1cm4gRSE9PUVycm9yLnByb3RvdHlwZX0sbj0+biE9PSJpc0F4aW9zRXJyb3IiKSxXLmNhbGwoZyxBLm1lc3NhZ2UsZSx0LEksciksZy5jYXVzZT1BLGcubmFtZT1BLm5hbWUsaSYmT2JqZWN0LmFzc2lnbihnLGkpLGd9O3ZhciBsPVc7dmFyIGhBPW51bGw7ZnVuY3Rpb24gS0EoQSl7cmV0dXJuIHMuaXNQbGFpbk9iamVjdChBKXx8cy5pc0FycmF5KEEpfWZ1bmN0aW9uIE9lKEEpe3JldHVybiBzLmVuZHNXaXRoKEEsIltdIik/QS5zbGljZSgwLC0yKTpBfWZ1bmN0aW9uIExlKEEsZSx0KXtyZXR1cm4gQT9BLmNvbmNhdChlKS5tYXAoZnVuY3Rpb24ocixpKXtyZXR1cm4gcj1PZShyKSwhdCYmaT8iWyIrcisiXSI6cn0pLmpvaW4odD8iLiI6IiIpOmV9ZnVuY3Rpb24gSUkoQSl7cmV0dXJuIHMuaXNBcnJheShBKSYmIUEuc29tZShLQSl9dmFyIHJJPXMudG9GbGF0T2JqZWN0KHMse30sbnVsbCxmdW5jdGlvbihlKXtyZXR1cm4vXmlzW0EtWl0vLnRlc3QoZSl9KTtmdW5jdGlvbiBpSShBLGUsdCl7aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigidGFyZ2V0IG11c3QgYmUgYW4gb2JqZWN0Iik7ZT1lfHxuZXcoaEF8fEZvcm1EYXRhKSx0PXMudG9GbGF0T2JqZWN0KHQse21ldGFUb2tlbnM6ITAsZG90czohMSxpbmRleGVzOiExfSwhMSxmdW5jdGlvbihmLG0pe3JldHVybiFzLmlzVW5kZWZpbmVkKG1bZl0pfSk7bGV0IEk9dC5tZXRhVG9rZW5zLHI9dC52aXNpdG9yfHxCLGk9dC5kb3RzLGc9dC5pbmRleGVzLEU9KHQuQmxvYnx8dHlwZW9mIEJsb2I8InUiJiZCbG9iKSYmcy5pc1NwZWNDb21wbGlhbnRGb3JtKGUpO2lmKCFzLmlzRnVuY3Rpb24ocikpdGhyb3cgbmV3IFR5cGVFcnJvcigidmlzaXRvciBtdXN0IGJlIGEgZnVuY3Rpb24iKTtmdW5jdGlvbiBvKFEpe2lmKFE9PT1udWxsKXJldHVybiIiO2lmKHMuaXNEYXRlKFEpKXJldHVybiBRLnRvSVNPU3RyaW5nKCk7aWYoIUUmJnMuaXNCbG9iKFEpKXRocm93IG5ldyBsKCJCbG9iIGlzIG5vdCBzdXBwb3J0ZWQuIFVzZSBhIEJ1ZmZlciBpbnN0ZWFkLiIpO3JldHVybiBzLmlzQXJyYXlCdWZmZXIoUSl8fHMuaXNUeXBlZEFycmF5KFEpP0UmJnR5cGVvZiBCbG9iPT0iZnVuY3Rpb24iP25ldyBCbG9iKFtRXSk6QnVmZmVyLmZyb20oUSk6UX1mdW5jdGlvbiBCKFEsZixtKXtsZXQgdz1RO2lmKFEmJiFtJiZ0eXBlb2YgUT09Im9iamVjdCIpe2lmKHMuZW5kc1dpdGgoZiwie30iKSlmPUk/ZjpmLnNsaWNlKDAsLTIpLFE9SlNPTi5zdHJpbmdpZnkoUSk7ZWxzZSBpZihzLmlzQXJyYXkoUSkmJklJKFEpfHwocy5pc0ZpbGVMaXN0KFEpfHxzLmVuZHNXaXRoKGYsIltdIikpJiYodz1zLnRvQXJyYXkoUSkpKXJldHVybiBmPU9lKGYpLHcuZm9yRWFjaChmdW5jdGlvbihLLEpBKXshKHMuaXNVbmRlZmluZWQoSyl8fEs9PT1udWxsKSYmZS5hcHBlbmQoZz09PSEwP0xlKFtmXSxKQSxpKTpnPT09bnVsbD9mOmYrIltdIixvKEspKX0pLCExfXJldHVybiBLQShRKT8hMDooZS5hcHBlbmQoTGUobSxmLGkpLG8oUSkpLCExKX1sZXQgYz1bXSxhPU9iamVjdC5hc3NpZ24ockkse2RlZmF1bHRWaXNpdG9yOkIsY29udmVydFZhbHVlOm8saXNWaXNpdGFibGU6S0F9KTtmdW5jdGlvbiBDKFEsZil7aWYoIXMuaXNVbmRlZmluZWQoUSkpe2lmKGMuaW5kZXhPZihRKSE9PS0xKXRocm93IEVycm9yKCJDaXJjdWxhciByZWZlcmVuY2UgZGV0ZWN0ZWQgaW4gIitmLmpvaW4oIi4iKSk7Yy5wdXNoKFEpLHMuZm9yRWFjaChRLGZ1bmN0aW9uKHcsTyl7KCEocy5pc1VuZGVmaW5lZCh3KXx8dz09PW51bGwpJiZyLmNhbGwoZSx3LHMuaXNTdHJpbmcoTyk/Ty50cmltKCk6TyxmLGEpKT09PSEwJiZDKHcsZj9mLmNvbmNhdChPKTpbT10pfSksYy5wb3AoKX19aWYoIXMuaXNPYmplY3QoQSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiZGF0YSBtdXN0IGJlIGFuIG9iamVjdCIpO3JldHVybiBDKEEpLGV9dmFyIEo9aUk7ZnVuY3Rpb24gSmUoQSl7bGV0IGU9eyIhIjoiJTI1MjEiLCJcJyI6IiUyNTI3IiwiKCI6IiUyNTI4IiwiKSI6IiUyNTI5IiwifiI6IiUyNTdFIiwiJTI1MjAiOiIrIiwiJTI1MDAiOiJcXDAifTtyZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KEEpLnJlcGxhY2UoL1shXCcoKX5dfCUyNTIwfCUyNTAwL2csZnVuY3Rpb24oSSl7cmV0dXJuIGVbSV19KX1mdW5jdGlvbiBNZShBLGUpe3RoaXMuX3BhaXJzPVtdLEEmJkooQSx0aGlzLGUpfXZhciBiZT1NZS5wcm90b3R5cGU7YmUuYXBwZW5kPWZ1bmN0aW9uKGUsdCl7dGhpcy5fcGFpcnMucHVzaChbZSx0XSl9O2JlLnRvU3RyaW5nPWZ1bmN0aW9uKGUpe2xldCB0PWU/ZnVuY3Rpb24oSSl7cmV0dXJuIGUuY2FsbCh0aGlzLEksSmUpfTpKZTtyZXR1cm4gdGhpcy5fcGFpcnMubWFwKGZ1bmN0aW9uKHIpe3JldHVybiB0KHJbMF0pKyI9Iit0KHJbMV0pfSwiIikuam9pbigiJiIpfTt2YXIgZEE9TWU7ZnVuY3Rpb24gZ0koQSl7cmV0dXJuIGVuY29kZVVSSUNvbXBvbmVudChBKS5yZXBsYWNlKC8lMjUzQS9naSwiOiIpLnJlcGxhY2UoLyUyNTI0L2csIiQiKS5yZXBsYWNlKC8lMjUyQy9naSwiLCIpLnJlcGxhY2UoLyUyNTIwL2csIisiKS5yZXBsYWNlKC8lMjU1Qi9naSwiWyIpLnJlcGxhY2UoLyUyNTVEL2dpLCJdIil9ZnVuY3Rpb24gQUEoQSxlLHQpe2lmKCFlKXJldHVybiBBO2xldCBJPXQmJnQuZW5jb2RlfHxnSSxyPXQmJnQuc2VyaWFsaXplLGk7aWYocj9pPXIoZSx0KTppPXMuaXNVUkxTZWFyY2hQYXJhbXMoZSk/ZS50b1N0cmluZygpOm5ldyBkQShlLHQpLnRvU3RyaW5nKEkpLGkpe2xldCBnPUEuaW5kZXhPZigiJTIzIik7ZyE9PS0xJiYoQT1BLnNsaWNlKDAsZykpLEErPShBLmluZGV4T2YoIj8iKT09PS0xPyI/IjoiJiIpK2l9cmV0dXJuIEF9dmFyIHhBPWNsYXNze2NvbnN0cnVjdG9yKCl7dGhpcy5oYW5kbGVycz1bXX11c2UoZSx0LEkpe3JldHVybiB0aGlzLmhhbmRsZXJzLnB1c2goe2Z1bGZpbGxlZDplLHJlamVjdGVkOnQsc3luY2hyb25vdXM6ST9JLnN5bmNocm9ub3VzOiExLHJ1bldoZW46ST9JLnJ1bldoZW46bnVsbH0pLHRoaXMuaGFuZGxlcnMubGVuZ3RoLTF9ZWplY3QoZSl7dGhpcy5oYW5kbGVyc1tlXSYmKHRoaXMuaGFuZGxlcnNbZV09bnVsbCl9Y2xlYXIoKXt0aGlzLmhhbmRsZXJzJiYodGhpcy5oYW5kbGVycz1bXSl9Zm9yRWFjaChlKXtzLmZvckVhY2godGhpcy5oYW5kbGVycyxmdW5jdGlvbihJKXtJIT09bnVsbCYmZShJKX0pfX0sUEE9eEE7dmFyIG1BPXtzaWxlbnRKU09OUGFyc2luZzohMCxmb3JjZWRKU09OUGFyc2luZzohMCxjbGFyaWZ5VGltZW91dEVycm9yOiExfTt2YXIgSGU9dHlwZW9mIFVSTFNlYXJjaFBhcmFtczwidSI/VVJMU2VhcmNoUGFyYW1zOmRBO3ZhciBZZT10eXBlb2YgRm9ybURhdGE8InUiP0Zvcm1EYXRhOm51bGw7dmFyIHFlPXR5cGVvZiBCbG9iPCJ1Ij9CbG9iOm51bGw7dmFyIG9JPSgoKT0+e2xldCBBO3JldHVybiB0eXBlb2YgbmF2aWdhdG9yPCJ1IiYmKChBPW5hdmlnYXRvci5wcm9kdWN0KT09PSJSZWFjdE5hdGl2ZSJ8fEE9PT0iTmF0aXZlU2NyaXB0Inx8QT09PSJOUyIpPyExOnR5cGVvZiB3aW5kb3c8InUiJiZ0eXBlb2YgZG9jdW1lbnQ8InUifSkoKSxuST0oKCk9PnR5cGVvZiBXb3JrZXJHbG9iYWxTY29wZTwidSImJnNlbGYgaW5zdGFuY2VvZiBXb3JrZXJHbG9iYWxTY29wZSYmdHlwZW9mIHNlbGYuaW1wb3J0U2NyaXB0cz09ImZ1bmN0aW9uIikoKSxEPXtpc0Jyb3dzZXI6ITAsY2xhc3Nlczp7VVJMU2VhcmNoUGFyYW1zOkhlLEZvcm1EYXRhOlllLEJsb2I6cWV9LGlzU3RhbmRhcmRCcm93c2VyRW52Om9JLGlzU3RhbmRhcmRCcm93c2VyV2ViV29ya2VyRW52Om5JLHByb3RvY29sczpbImh0dHAiLCJodHRwcyIsImZpbGUiLCJibG9iIiwidXJsIiwiZGF0YSJdfTtmdW5jdGlvbiBXQShBLGUpe3JldHVybiBKKEEsbmV3IEQuY2xhc3Nlcy5VUkxTZWFyY2hQYXJhbXMsT2JqZWN0LmFzc2lnbih7dmlzaXRvcjpmdW5jdGlvbih0LEkscixpKXtyZXR1cm4gRC5pc05vZGUmJnMuaXNCdWZmZXIodCk/KHRoaXMuYXBwZW5kKEksdC50b1N0cmluZygiYmFzZTY0IikpLCExKTppLmRlZmF1bHRWaXNpdG9yLmFwcGx5KHRoaXMsYXJndW1lbnRzKX19LGUpKX1mdW5jdGlvbiBhSShBKXtyZXR1cm4gcy5tYXRjaEFsbCgvXFx3K3xcXFsoXFx3KildL2csQSkubWFwKGU9PmVbMF09PT0iW10iPyIiOmVbMV18fGVbMF0pfWZ1bmN0aW9uIHNJKEEpe2xldCBlPXt9LHQ9T2JqZWN0LmtleXMoQSksSSxyPXQubGVuZ3RoLGk7Zm9yKEk9MDtJPHI7SSsrKWk9dFtJXSxlW2ldPUFbaV07cmV0dXJuIGV9ZnVuY3Rpb24gQ0koQSl7ZnVuY3Rpb24gZSh0LEkscixpKXtsZXQgZz10W2krK10sbj1OdW1iZXIuaXNGaW5pdGUoK2cpLEU9aT49dC5sZW5ndGg7cmV0dXJuIGc9IWcmJnMuaXNBcnJheShyKT9yLmxlbmd0aDpnLEU/KHMuaGFzT3duUHJvcChyLGcpP3JbZ109W3JbZ10sSV06cltnXT1JLCFuKTooKCFyW2ddfHwhcy5pc09iamVjdChyW2ddKSkmJihyW2ddPVtdKSxlKHQsSSxyW2ddLGkpJiZzLmlzQXJyYXkocltnXSkmJihyW2ddPXNJKHJbZ10pKSwhbil9aWYocy5pc0Zvcm1EYXRhKEEpJiZzLmlzRnVuY3Rpb24oQS5lbnRyaWVzKSl7bGV0IHQ9e307cmV0dXJuIHMuZm9yRWFjaEVudHJ5KEEsKEkscik9PntlKGFJKEkpLHIsdCwwKX0pLHR9cmV0dXJuIG51bGx9dmFyIERBPUNJO3ZhciBCST17IkNvbnRlbnQtVHlwZSI6dm9pZCAwfTtmdW5jdGlvbiBRSShBLGUsdCl7aWYocy5pc1N0cmluZyhBKSl0cnl7cmV0dXJuKGV8fEpTT04ucGFyc2UpKEEpLHMudHJpbShBKX1jYXRjaChJKXtpZihJLm5hbWUhPT0iU3ludGF4RXJyb3IiKXRocm93IEl9cmV0dXJuKHR8fEpTT04uc3RyaW5naWZ5KShBKX12YXIgeUE9e3RyYW5zaXRpb25hbDptQSxhZGFwdGVyOlsieGhyIiwiaHR0cCJdLHRyYW5zZm9ybVJlcXVlc3Q6W2Z1bmN0aW9uKGUsdCl7bGV0IEk9dC5nZXRDb250ZW50VHlwZSgpfHwiIixyPUkuaW5kZXhPZigiYXBwbGljYXRpb24vanNvbiIpPi0xLGk9cy5pc09iamVjdChlKTtpZihpJiZzLmlzSFRNTEZvcm0oZSkmJihlPW5ldyBGb3JtRGF0YShlKSkscy5pc0Zvcm1EYXRhKGUpKXJldHVybiByJiZyP0pTT04uc3RyaW5naWZ5KERBKGUpKTplO2lmKHMuaXNBcnJheUJ1ZmZlcihlKXx8cy5pc0J1ZmZlcihlKXx8cy5pc1N0cmVhbShlKXx8cy5pc0ZpbGUoZSl8fHMuaXNCbG9iKGUpKXJldHVybiBlO2lmKHMuaXNBcnJheUJ1ZmZlclZpZXcoZSkpcmV0dXJuIGUuYnVmZmVyO2lmKHMuaXNVUkxTZWFyY2hQYXJhbXMoZSkpcmV0dXJuIHQuc2V0Q29udGVudFR5cGUoImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDtjaGFyc2V0PXV0Zi04IiwhMSksZS50b1N0cmluZygpO2xldCBuO2lmKGkpe2lmKEkuaW5kZXhPZigiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIik+LTEpcmV0dXJuIFdBKGUsdGhpcy5mb3JtU2VyaWFsaXplcikudG9TdHJpbmcoKTtpZigobj1zLmlzRmlsZUxpc3QoZSkpfHxJLmluZGV4T2YoIm11bHRpcGFydC9mb3JtLWRhdGEiKT4tMSl7bGV0IEU9dGhpcy5lbnYmJnRoaXMuZW52LkZvcm1EYXRhO3JldHVybiBKKG4/eyJmaWxlc1tdIjplfTplLEUmJm5ldyBFLHRoaXMuZm9ybVNlcmlhbGl6ZXIpfX1yZXR1cm4gaXx8cj8odC5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24vanNvbiIsITEpLFFJKGUpKTplfV0sdHJhbnNmb3JtUmVzcG9uc2U6W2Z1bmN0aW9uKGUpe2xldCB0PXRoaXMudHJhbnNpdGlvbmFsfHx5QS50cmFuc2l0aW9uYWwsST10JiZ0LmZvcmNlZEpTT05QYXJzaW5nLHI9dGhpcy5yZXNwb25zZVR5cGU9PT0ianNvbiI7aWYoZSYmcy5pc1N0cmluZyhlKSYmKEkmJiF0aGlzLnJlc3BvbnNlVHlwZXx8cikpe2xldCBnPSEodCYmdC5zaWxlbnRKU09OUGFyc2luZykmJnI7dHJ5e3JldHVybiBKU09OLnBhcnNlKGUpfWNhdGNoKG4pe2lmKGcpdGhyb3cgbi5uYW1lPT09IlN5bnRheEVycm9yIj9sLmZyb20obixsLkVSUl9CQURfUkVTUE9OU0UsdGhpcyxudWxsLHRoaXMucmVzcG9uc2UpOm59fXJldHVybiBlfV0sdGltZW91dDowLHhzcmZDb29raWVOYW1lOiJYU1JGLVRPS0VOIix4c3JmSGVhZGVyTmFtZToiWC1YU1JGLVRPS0VOIixtYXhDb250ZW50TGVuZ3RoOi0xLG1heEJvZHlMZW5ndGg6LTEsZW52OntGb3JtRGF0YTpELmNsYXNzZXMuRm9ybURhdGEsQmxvYjpELmNsYXNzZXMuQmxvYn0sdmFsaWRhdGVTdGF0dXM6ZnVuY3Rpb24oZSl7cmV0dXJuIGU+PTIwMCYmZTwzMDB9LGhlYWRlcnM6e2NvbW1vbjp7QWNjZXB0OiJhcHBsaWNhdGlvbi9qc29uLCB0ZXh0L3BsYWluLCAqLyoifX19O3MuZm9yRWFjaChbImRlbGV0ZSIsImdldCIsImhlYWQiXSxmdW5jdGlvbihlKXt5QS5oZWFkZXJzW2VdPXt9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7eUEuaGVhZGVyc1tlXT1zLm1lcmdlKEJJKX0pO3ZhciBqPXlBO3ZhciBFST1zLnRvT2JqZWN0U2V0KFsiYWdlIiwiYXV0aG9yaXphdGlvbiIsImNvbnRlbnQtbGVuZ3RoIiwiY29udGVudC10eXBlIiwiZXRhZyIsImV4cGlyZXMiLCJmcm9tIiwiaG9zdCIsImlmLW1vZGlmaWVkLXNpbmNlIiwiaWYtdW5tb2RpZmllZC1zaW5jZSIsImxhc3QtbW9kaWZpZWQiLCJsb2NhdGlvbiIsIm1heC1mb3J3YXJkcyIsInByb3h5LWF1dGhvcml6YXRpb24iLCJyZWZlcmVyIiwicmV0cnktYWZ0ZXIiLCJ1c2VyLWFnZW50Il0pLFRlPUE9PntsZXQgZT17fSx0LEkscjtyZXR1cm4gQSYmQS5zcGxpdChgJTBBYCkuZm9yRWFjaChmdW5jdGlvbihnKXtyPWcuaW5kZXhPZigiOiIpLHQ9Zy5zdWJzdHJpbmcoMCxyKS50cmltKCkudG9Mb3dlckNhc2UoKSxJPWcuc3Vic3RyaW5nKHIrMSkudHJpbSgpLCEoIXR8fGVbdF0mJkVJW3RdKSYmKHQ9PT0ic2V0LWNvb2tpZSI/ZVt0XT9lW3RdLnB1c2goSSk6ZVt0XT1bSV06ZVt0XT1lW3RdP2VbdF0rIiwgIitJOkkpfSksZX07dmFyIEtlPVN5bWJvbCgiaW50ZXJuYWxzIik7ZnVuY3Rpb24gZUEoQSl7cmV0dXJuIEEmJlN0cmluZyhBKS50cmltKCkudG9Mb3dlckNhc2UoKX1mdW5jdGlvbiB3QShBKXtyZXR1cm4gQT09PSExfHxBPT1udWxsP0E6cy5pc0FycmF5KEEpP0EubWFwKHdBKTpTdHJpbmcoQSl9ZnVuY3Rpb24gY0koQSl7bGV0IGU9T2JqZWN0LmNyZWF0ZShudWxsKSx0PS8oW15cXHMsOz1dKylcXHMqKD86PVxccyooW14sO10rKSk/L2csSTtmb3IoO0k9dC5leGVjKEEpOyllW0lbMV1dPUlbMl07cmV0dXJuIGV9dmFyIGZJPUE9Pi9eWy1fYS16QS1aMC05XmB8fiwhJTIzJCUmXCcqKy5dKyQvLnRlc3QoQS50cmltKCkpO2Z1bmN0aW9uIGpBKEEsZSx0LEkscil7aWYocy5pc0Z1bmN0aW9uKEkpKXJldHVybiBJLmNhbGwodGhpcyxlLHQpO2lmKHImJihlPXQpLCEhcy5pc1N0cmluZyhlKSl7aWYocy5pc1N0cmluZyhJKSlyZXR1cm4gZS5pbmRleE9mKEkpIT09LTE7aWYocy5pc1JlZ0V4cChJKSlyZXR1cm4gSS50ZXN0KGUpfX1mdW5jdGlvbiBsSShBKXtyZXR1cm4gQS50cmltKCkudG9Mb3dlckNhc2UoKS5yZXBsYWNlKC8oW2EtelxcZF0pKFxcdyopL2csKGUsdCxJKT0+dC50b1VwcGVyQ2FzZSgpK0kpfWZ1bmN0aW9uIHVJKEEsZSl7bGV0IHQ9cy50b0NhbWVsQ2FzZSgiICIrZSk7WyJnZXQiLCJzZXQiLCJoYXMiXS5mb3JFYWNoKEk9PntPYmplY3QuZGVmaW5lUHJvcGVydHkoQSxJK3Qse3ZhbHVlOmZ1bmN0aW9uKHIsaSxnKXtyZXR1cm4gdGhpc1tJXS5jYWxsKHRoaXMsZSxyLGksZyl9LGNvbmZpZ3VyYWJsZTohMH0pfSl9dmFyIFo9Y2xhc3N7Y29uc3RydWN0b3IoZSl7ZSYmdGhpcy5zZXQoZSl9c2V0KGUsdCxJKXtsZXQgcj10aGlzO2Z1bmN0aW9uIGkobixFLG8pe2xldCBCPWVBKEUpO2lmKCFCKXRocm93IG5ldyBFcnJvcigiaGVhZGVyIG5hbWUgbXVzdCBiZSBhIG5vbi1lbXB0eSBzdHJpbmciKTtsZXQgYz1zLmZpbmRLZXkocixCKTsoIWN8fHJbY109PT12b2lkIDB8fG89PT0hMHx8bz09PXZvaWQgMCYmcltjXSE9PSExKSYmKHJbY3x8RV09d0EobikpfWxldCBnPShuLEUpPT5zLmZvckVhY2gobiwobyxCKT0+aShvLEIsRSkpO3JldHVybiBzLmlzUGxhaW5PYmplY3QoZSl8fGUgaW5zdGFuY2VvZiB0aGlzLmNvbnN0cnVjdG9yP2coZSx0KTpzLmlzU3RyaW5nKGUpJiYoZT1lLnRyaW0oKSkmJiFmSShlKT9nKFRlKGUpLHQpOmUhPW51bGwmJmkodCxlLEkpLHRoaXN9Z2V0KGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtpZihJKXtsZXQgcj10aGlzW0ldO2lmKCF0KXJldHVybiByO2lmKHQ9PT0hMClyZXR1cm4gY0kocik7aWYocy5pc0Z1bmN0aW9uKHQpKXJldHVybiB0LmNhbGwodGhpcyxyLEkpO2lmKHMuaXNSZWdFeHAodCkpcmV0dXJuIHQuZXhlYyhyKTt0aHJvdyBuZXcgVHlwZUVycm9yKCJwYXJzZXIgbXVzdCBiZSBib29sZWFufHJlZ2V4cHxmdW5jdGlvbiIpfX19aGFzKGUsdCl7aWYoZT1lQShlKSxlKXtsZXQgST1zLmZpbmRLZXkodGhpcyxlKTtyZXR1cm4hIShJJiZ0aGlzW0ldIT09dm9pZCAwJiYoIXR8fGpBKHRoaXMsdGhpc1tJXSxJLHQpKSl9cmV0dXJuITF9ZGVsZXRlKGUsdCl7bGV0IEk9dGhpcyxyPSExO2Z1bmN0aW9uIGkoZyl7aWYoZz1lQShnKSxnKXtsZXQgbj1zLmZpbmRLZXkoSSxnKTtuJiYoIXR8fGpBKEksSVtuXSxuLHQpKSYmKGRlbGV0ZSBJW25dLHI9ITApfX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHJ9Y2xlYXIoZSl7bGV0IHQ9T2JqZWN0LmtleXModGhpcyksST10Lmxlbmd0aCxyPSExO2Zvcig7SS0tOyl7bGV0IGk9dFtJXTsoIWV8fGpBKHRoaXMsdGhpc1tpXSxpLGUsITApKSYmKGRlbGV0ZSB0aGlzW2ldLHI9ITApfXJldHVybiByfW5vcm1hbGl6ZShlKXtsZXQgdD10aGlzLEk9e307cmV0dXJuIHMuZm9yRWFjaCh0aGlzLChyLGkpPT57bGV0IGc9cy5maW5kS2V5KEksaSk7aWYoZyl7dFtnXT13QShyKSxkZWxldGUgdFtpXTtyZXR1cm59bGV0IG49ZT9sSShpKTpTdHJpbmcoaSkudHJpbSgpO24hPT1pJiZkZWxldGUgdFtpXSx0W25dPXdBKHIpLElbbl09ITB9KSx0aGlzfWNvbmNhdCguLi5lKXtyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci5jb25jYXQodGhpcywuLi5lKX10b0pTT04oZSl7bGV0IHQ9T2JqZWN0LmNyZWF0ZShudWxsKTtyZXR1cm4gcy5mb3JFYWNoKHRoaXMsKEkscik9PntJIT1udWxsJiZJIT09ITEmJih0W3JdPWUmJnMuaXNBcnJheShJKT9JLmpvaW4oIiwgIik6SSl9KSx0fVtTeW1ib2wuaXRlcmF0b3JdKCl7cmV0dXJuIE9iamVjdC5lbnRyaWVzKHRoaXMudG9KU09OKCkpW1N5bWJvbC5pdGVyYXRvcl0oKX10b1N0cmluZygpe3JldHVybiBPYmplY3QuZW50cmllcyh0aGlzLnRvSlNPTigpKS5tYXAoKFtlLHRdKT0+ZSsiOiAiK3QpLmpvaW4oYCUwQWApfWdldFtTeW1ib2wudG9TdHJpbmdUYWddKCl7cmV0dXJuIkF4aW9zSGVhZGVycyJ9c3RhdGljIGZyb20oZSl7cmV0dXJuIGUgaW5zdGFuY2VvZiB0aGlzP2U6bmV3IHRoaXMoZSl9c3RhdGljIGNvbmNhdChlLC4uLnQpe2xldCBJPW5ldyB0aGlzKGUpO3JldHVybiB0LmZvckVhY2gocj0+SS5zZXQocikpLEl9c3RhdGljIGFjY2Vzc29yKGUpe2xldCBJPSh0aGlzW0tlXT10aGlzW0tlXT17YWNjZXNzb3JzOnt9fSkuYWNjZXNzb3JzLHI9dGhpcy5wcm90b3R5cGU7ZnVuY3Rpb24gaShnKXtsZXQgbj1lQShnKTtJW25dfHwodUkocixnKSxJW25dPSEwKX1yZXR1cm4gcy5pc0FycmF5KGUpP2UuZm9yRWFjaChpKTppKGUpLHRoaXN9fTtaLmFjY2Vzc29yKFsiQ29udGVudC1UeXBlIiwiQ29udGVudC1MZW5ndGgiLCJBY2NlcHQiLCJBY2NlcHQtRW5jb2RpbmciLCJVc2VyLUFnZW50IiwiQXV0aG9yaXphdGlvbiJdKTtzLmZyZWV6ZU1ldGhvZHMoWi5wcm90b3R5cGUpO3MuZnJlZXplTWV0aG9kcyhaKTt2YXIgcD1aO2Z1bmN0aW9uIHRBKEEsZSl7bGV0IHQ9dGhpc3x8aixJPWV8fHQscj1wLmZyb20oSS5oZWFkZXJzKSxpPUkuZGF0YTtyZXR1cm4gcy5mb3JFYWNoKEEsZnVuY3Rpb24obil7aT1uLmNhbGwodCxpLHIubm9ybWFsaXplKCksZT9lLnN0YXR1czp2b2lkIDApfSksci5ub3JtYWxpemUoKSxpfWZ1bmN0aW9uIElBKEEpe3JldHVybiEhKEEmJkEuX19DQU5DRUxfXyl9ZnVuY3Rpb24geGUoQSxlLHQpe2wuY2FsbCh0aGlzLEE/PyJjYW5jZWxlZCIsbC5FUlJfQ0FOQ0VMRUQsZSx0KSx0aGlzLm5hbWU9IkNhbmNlbGVkRXJyb3IifXMuaW5oZXJpdHMoeGUsbCx7X19DQU5DRUxfXzohMH0pO3ZhciBNPXhlO2Z1bmN0aW9uIFpBKEEsZSx0KXtsZXQgST10LmNvbmZpZy52YWxpZGF0ZVN0YXR1czshdC5zdGF0dXN8fCFJfHxJKHQuc3RhdHVzKT9BKHQpOmUobmV3IGwoIlJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzIGNvZGUgIit0LnN0YXR1cyxbbC5FUlJfQkFEX1JFUVVFU1QsbC5FUlJfQkFEX1JFU1BPTlNFXVtNYXRoLmZsb29yKHQuc3RhdHVzLzEwMCktNF0sdC5jb25maWcsdC5yZXF1ZXN0LHQpKX12YXIgUGU9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbih0LEkscixpLGcsbil7bGV0IEU9W107RS5wdXNoKHQrIj0iK2VuY29kZVVSSUNvbXBvbmVudChJKSkscy5pc051bWJlcihyKSYmRS5wdXNoKCJleHBpcmVzPSIrbmV3IERhdGUocikudG9HTVRTdHJpbmcoKSkscy5pc1N0cmluZyhpKSYmRS5wdXNoKCJwYXRoPSIraSkscy5pc1N0cmluZyhnKSYmRS5wdXNoKCJkb21haW49IitnKSxuPT09ITAmJkUucHVzaCgic2VjdXJlIiksZG9jdW1lbnQuY29va2llPUUuam9pbigiOyAiKX0scmVhZDpmdW5jdGlvbih0KXtsZXQgST1kb2N1bWVudC5jb29raWUubWF0Y2gobmV3IFJlZ0V4cCgiKF58O1xcXFxzKikoIit0KyIpPShbXjtdKikiKSk7cmV0dXJuIEk/ZGVjb2RlVVJJQ29tcG9uZW50KElbM10pOm51bGx9LHJlbW92ZTpmdW5jdGlvbih0KXt0aGlzLndyaXRlKHQsIiIsRGF0ZS5ub3coKS04NjRlNSl9fX0oKTpmdW5jdGlvbigpe3JldHVybnt3cml0ZTpmdW5jdGlvbigpe30scmVhZDpmdW5jdGlvbigpe3JldHVybiBudWxsfSxyZW1vdmU6ZnVuY3Rpb24oKXt9fX0oKTtmdW5jdGlvbiBfQShBKXtyZXR1cm4vXihbYS16XVthLXpcXGQrXFwtLl0qOik/XFwvXFwvL2kudGVzdChBKX1mdW5jdGlvbiBWQShBLGUpe3JldHVybiBlP0EucmVwbGFjZSgvXFwvKyQvLCIiKSsiLyIrZS5yZXBsYWNlKC9eXFwvKy8sIiIpOkF9ZnVuY3Rpb24gckEoQSxlKXtyZXR1cm4gQSYmIV9BKGUpP1ZBKEEsZSk6ZX12YXIgV2U9RC5pc1N0YW5kYXJkQnJvd3NlckVudj9mdW5jdGlvbigpe2xldCBlPS8obXNpZXx0cmlkZW50KS9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCksdD1kb2N1bWVudC5jcmVhdGVFbGVtZW50KCJhIiksSTtmdW5jdGlvbiByKGkpe2xldCBnPWk7cmV0dXJuIGUmJih0LnNldEF0dHJpYnV0ZSgiaHJlZiIsZyksZz10LmhyZWYpLHQuc2V0QXR0cmlidXRlKCJocmVmIixnKSx7aHJlZjp0LmhyZWYscHJvdG9jb2w6dC5wcm90b2NvbD90LnByb3RvY29sLnJlcGxhY2UoLzokLywiIik6IiIsaG9zdDp0Lmhvc3Qsc2VhcmNoOnQuc2VhcmNoP3Quc2VhcmNoLnJlcGxhY2UoL15cXD8vLCIiKToiIixoYXNoOnQuaGFzaD90Lmhhc2gucmVwbGFjZSgvXiUyMy8sIiIpOiIiLGhvc3RuYW1lOnQuaG9zdG5hbWUscG9ydDp0LnBvcnQscGF0aG5hbWU6dC5wYXRobmFtZS5jaGFyQXQoMCk9PT0iLyI/dC5wYXRobmFtZToiLyIrdC5wYXRobmFtZX19cmV0dXJuIEk9cih3aW5kb3cubG9jYXRpb24uaHJlZiksZnVuY3Rpb24oZyl7bGV0IG49cy5pc1N0cmluZyhnKT9yKGcpOmc7cmV0dXJuIG4ucHJvdG9jb2w9PT1JLnByb3RvY29sJiZuLmhvc3Q9PT1JLmhvc3R9fSgpOmZ1bmN0aW9uKCl7cmV0dXJuIGZ1bmN0aW9uKCl7cmV0dXJuITB9fSgpO2Z1bmN0aW9uIHpBKEEpe2xldCBlPS9eKFstK1xcd117MSwyNX0pKDo/XFwvXFwvfDopLy5leGVjKEEpO3JldHVybiBlJiZlWzFdfHwiIn1mdW5jdGlvbiBoSShBLGUpe0E9QXx8MTA7bGV0IHQ9bmV3IEFycmF5KEEpLEk9bmV3IEFycmF5KEEpLHI9MCxpPTAsZztyZXR1cm4gZT1lIT09dm9pZCAwP2U6MWUzLGZ1bmN0aW9uKEUpe2xldCBvPURhdGUubm93KCksQj1JW2ldO2d8fChnPW8pLHRbcl09RSxJW3JdPW87bGV0IGM9aSxhPTA7Zm9yKDtjIT09cjspYSs9dFtjKytdLGM9YyVBO2lmKHI9KHIrMSklQSxyPT09aSYmKGk9KGkrMSklQSksby1nPGUpcmV0dXJuO2xldCBDPUImJm8tQjtyZXR1cm4gQz9NYXRoLnJvdW5kKGEqMWUzL0MpOnZvaWQgMH19dmFyIGplPWhJO2Z1bmN0aW9uIFplKEEsZSl7bGV0IHQ9MCxJPWplKDUwLDI1MCk7cmV0dXJuIHI9PntsZXQgaT1yLmxvYWRlZCxnPXIubGVuZ3RoQ29tcHV0YWJsZT9yLnRvdGFsOnZvaWQgMCxuPWktdCxFPUkobiksbz1pPD1nO3Q9aTtsZXQgQj17bG9hZGVkOmksdG90YWw6Zyxwcm9ncmVzczpnP2kvZzp2b2lkIDAsYnl0ZXM6bixyYXRlOkV8fHZvaWQgMCxlc3RpbWF0ZWQ6RSYmZyYmbz8oZy1pKS9FOnZvaWQgMCxldmVudDpyfTtCW2U/ImRvd25sb2FkIjoidXBsb2FkIl09ITAsQShCKX19dmFyIGRJPXR5cGVvZiBYTUxIdHRwUmVxdWVzdDwidSIsX2U9ZEkmJmZ1bmN0aW9uKEEpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbih0LEkpe2xldCByPUEuZGF0YSxpPXAuZnJvbShBLmhlYWRlcnMpLm5vcm1hbGl6ZSgpLGc9QS5yZXNwb25zZVR5cGUsbjtmdW5jdGlvbiBFKCl7QS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi51bnN1YnNjcmliZShuKSxBLnNpZ25hbCYmQS5zaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigiYWJvcnQiLG4pfXMuaXNGb3JtRGF0YShyKSYmKEQuaXNTdGFuZGFyZEJyb3dzZXJFbnZ8fEQuaXNTdGFuZGFyZEJyb3dzZXJXZWJXb3JrZXJFbnY/aS5zZXRDb250ZW50VHlwZSghMSk6aS5zZXRDb250ZW50VHlwZSgibXVsdGlwYXJ0L2Zvcm0tZGF0YTsiLCExKSk7bGV0IG89bmV3IFhNTEh0dHBSZXF1ZXN0O2lmKEEuYXV0aCl7bGV0IEM9QS5hdXRoLnVzZXJuYW1lfHwiIixRPUEuYXV0aC5wYXNzd29yZD91bmVzY2FwZShlbmNvZGVVUklDb21wb25lbnQoQS5hdXRoLnBhc3N3b3JkKSk6IiI7aS5zZXQoIkF1dGhvcml6YXRpb24iLCJCYXNpYyAiK2J0b2EoQysiOiIrUSkpfWxldCBCPXJBKEEuYmFzZVVSTCxBLnVybCk7by5vcGVuKEEubWV0aG9kLnRvVXBwZXJDYXNlKCksQUEoQixBLnBhcmFtcyxBLnBhcmFtc1NlcmlhbGl6ZXIpLCEwKSxvLnRpbWVvdXQ9QS50aW1lb3V0O2Z1bmN0aW9uIGMoKXtpZighbylyZXR1cm47bGV0IEM9cC5mcm9tKCJnZXRBbGxSZXNwb25zZUhlYWRlcnMiaW4gbyYmby5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKSksZj17ZGF0YTohZ3x8Zz09PSJ0ZXh0Inx8Zz09PSJqc29uIj9vLnJlc3BvbnNlVGV4dDpvLnJlc3BvbnNlLHN0YXR1czpvLnN0YXR1cyxzdGF0dXNUZXh0Om8uc3RhdHVzVGV4dCxoZWFkZXJzOkMsY29uZmlnOkEscmVxdWVzdDpvfTtaQShmdW5jdGlvbih3KXt0KHcpLEUoKX0sZnVuY3Rpb24odyl7SSh3KSxFKCl9LGYpLG89bnVsbH1pZigib25sb2FkZW5kImluIG8/by5vbmxvYWRlbmQ9YzpvLm9ucmVhZHlzdGF0ZWNoYW5nZT1mdW5jdGlvbigpeyFvfHxvLnJlYWR5U3RhdGUhPT00fHxvLnN0YXR1cz09PTAmJiEoby5yZXNwb25zZVVSTCYmby5yZXNwb25zZVVSTC5pbmRleE9mKCJmaWxlOiIpPT09MCl8fHNldFRpbWVvdXQoYyl9LG8ub25hYm9ydD1mdW5jdGlvbigpe28mJihJKG5ldyBsKCJSZXF1ZXN0IGFib3J0ZWQiLGwuRUNPTk5BQk9SVEVELEEsbykpLG89bnVsbCl9LG8ub25lcnJvcj1mdW5jdGlvbigpe0kobmV3IGwoIk5ldHdvcmsgRXJyb3IiLGwuRVJSX05FVFdPUkssQSxvKSksbz1udWxsfSxvLm9udGltZW91dD1mdW5jdGlvbigpe2xldCBRPUEudGltZW91dD8idGltZW91dCBvZiAiK0EudGltZW91dCsibXMgZXhjZWVkZWQiOiJ0aW1lb3V0IGV4Y2VlZGVkIixmPUEudHJhbnNpdGlvbmFsfHxtQTtBLnRpbWVvdXRFcnJvck1lc3NhZ2UmJihRPUEudGltZW91dEVycm9yTWVzc2FnZSksSShuZXcgbChRLGYuY2xhcmlmeVRpbWVvdXRFcnJvcj9sLkVUSU1FRE9VVDpsLkVDT05OQUJPUlRFRCxBLG8pKSxvPW51bGx9LEQuaXNTdGFuZGFyZEJyb3dzZXJFbnYpe2xldCBDPShBLndpdGhDcmVkZW50aWFsc3x8V2UoQikpJiZBLnhzcmZDb29raWVOYW1lJiZQZS5yZWFkKEEueHNyZkNvb2tpZU5hbWUpO0MmJmkuc2V0KEEueHNyZkhlYWRlck5hbWUsQyl9cj09PXZvaWQgMCYmaS5zZXRDb250ZW50VHlwZShudWxsKSwic2V0UmVxdWVzdEhlYWRlciJpbiBvJiZzLmZvckVhY2goaS50b0pTT04oKSxmdW5jdGlvbihRLGYpe28uc2V0UmVxdWVzdEhlYWRlcihmLFEpfSkscy5pc1VuZGVmaW5lZChBLndpdGhDcmVkZW50aWFscyl8fChvLndpdGhDcmVkZW50aWFscz0hIUEud2l0aENyZWRlbnRpYWxzKSxnJiZnIT09Impzb24iJiYoby5yZXNwb25zZVR5cGU9QS5yZXNwb25zZVR5cGUpLHR5cGVvZiBBLm9uRG93bmxvYWRQcm9ncmVzcz09ImZ1bmN0aW9uIiYmby5hZGRFdmVudExpc3RlbmVyKCJwcm9ncmVzcyIsWmUoQS5vbkRvd25sb2FkUHJvZ3Jlc3MsITApKSx0eXBlb2YgQS5vblVwbG9hZFByb2dyZXNzPT0iZnVuY3Rpb24iJiZvLnVwbG9hZCYmby51cGxvYWQuYWRkRXZlbnRMaXN0ZW5lcigicHJvZ3Jlc3MiLFplKEEub25VcGxvYWRQcm9ncmVzcykpLChBLmNhbmNlbFRva2VufHxBLnNpZ25hbCkmJihuPUM9PntvJiYoSSghQ3x8Qy50eXBlP25ldyBNKG51bGwsQSxvKTpDKSxvLmFib3J0KCksbz1udWxsKX0sQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi5zdWJzY3JpYmUobiksQS5zaWduYWwmJihBLnNpZ25hbC5hYm9ydGVkP24oKTpBLnNpZ25hbC5hZGRFdmVudExpc3RlbmVyKCJhYm9ydCIsbikpKTtsZXQgYT16QShCKTtpZihhJiZELnByb3RvY29scy5pbmRleE9mKGEpPT09LTEpe0kobmV3IGwoIlVuc3VwcG9ydGVkIHByb3RvY29sICIrYSsiOiIsbC5FUlJfQkFEX1JFUVVFU1QsQSkpO3JldHVybn1vLnNlbmQocnx8bnVsbCl9KX07dmFyIHBBPXtodHRwOmhBLHhocjpfZX07cy5mb3JFYWNoKHBBLChBLGUpPT57aWYoQSl7dHJ5e09iamVjdC5kZWZpbmVQcm9wZXJ0eShBLCJuYW1lIix7dmFsdWU6ZX0pfWNhdGNoe31PYmplY3QuZGVmaW5lUHJvcGVydHkoQSwiYWRhcHRlck5hbWUiLHt2YWx1ZTplfSl9fSk7dmFyIFZlPXtnZXRBZGFwdGVyOkE9PntBPXMuaXNBcnJheShBKT9BOltBXTtsZXR7bGVuZ3RoOmV9PUEsdCxJO2ZvcihsZXQgcj0wO3I8ZSYmKHQ9QVtyXSwhKEk9cy5pc1N0cmluZyh0KT9wQVt0LnRvTG93ZXJDYXNlKCldOnQpKTtyKyspO2lmKCFJKXRocm93IEk9PT0hMT9uZXcgbChgQWRhcHRlciAke3R9IGlzIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGVudmlyb25tZW50YCwiRVJSX05PVF9TVVBQT1JUIik6bmV3IEVycm9yKHMuaGFzT3duUHJvcChwQSx0KT9gQWRhcHRlciBcJyR7dH1cJyBpcyBub3QgYXZhaWxhYmxlIGluIHRoZSBidWlsZGA6YFVua25vd24gYWRhcHRlciBcJyR7dH1cJ2ApO2lmKCFzLmlzRnVuY3Rpb24oSSkpdGhyb3cgbmV3IFR5cGVFcnJvcigiYWRhcHRlciBpcyBub3QgYSBmdW5jdGlvbiIpO3JldHVybiBJfSxhZGFwdGVyczpwQX07ZnVuY3Rpb24gWEEoQSl7aWYoQS5jYW5jZWxUb2tlbiYmQS5jYW5jZWxUb2tlbi50aHJvd0lmUmVxdWVzdGVkKCksQS5zaWduYWwmJkEuc2lnbmFsLmFib3J0ZWQpdGhyb3cgbmV3IE0obnVsbCxBKX1mdW5jdGlvbiBGQShBKXtyZXR1cm4gWEEoQSksQS5oZWFkZXJzPXAuZnJvbShBLmhlYWRlcnMpLEEuZGF0YT10QS5jYWxsKEEsQS50cmFuc2Zvcm1SZXF1ZXN0KSxbInBvc3QiLCJwdXQiLCJwYXRjaCJdLmluZGV4T2YoQS5tZXRob2QpIT09LTEmJkEuaGVhZGVycy5zZXRDb250ZW50VHlwZSgiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkIiwhMSksVmUuZ2V0QWRhcHRlcihBLmFkYXB0ZXJ8fGouYWRhcHRlcikoQSkudGhlbihmdW5jdGlvbihJKXtyZXR1cm4gWEEoQSksSS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkpLEkuaGVhZGVycz1wLmZyb20oSS5oZWFkZXJzKSxJfSxmdW5jdGlvbihJKXtyZXR1cm4gSUEoSSl8fChYQShBKSxJJiZJLnJlc3BvbnNlJiYoSS5yZXNwb25zZS5kYXRhPXRBLmNhbGwoQSxBLnRyYW5zZm9ybVJlc3BvbnNlLEkucmVzcG9uc2UpLEkucmVzcG9uc2UuaGVhZGVycz1wLmZyb20oSS5yZXNwb25zZS5oZWFkZXJzKSkpLFByb21pc2UucmVqZWN0KEkpfSl9dmFyIHplPUE9PkEgaW5zdGFuY2VvZiBwP0EudG9KU09OKCk6QTtmdW5jdGlvbiBrKEEsZSl7ZT1lfHx7fTtsZXQgdD17fTtmdW5jdGlvbiBJKG8sQixjKXtyZXR1cm4gcy5pc1BsYWluT2JqZWN0KG8pJiZzLmlzUGxhaW5PYmplY3QoQik/cy5tZXJnZS5jYWxsKHtjYXNlbGVzczpjfSxvLEIpOnMuaXNQbGFpbk9iamVjdChCKT9zLm1lcmdlKHt9LEIpOnMuaXNBcnJheShCKT9CLnNsaWNlKCk6Qn1mdW5jdGlvbiByKG8sQixjKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyxjKX1lbHNlIHJldHVybiBJKG8sQixjKX1mdW5jdGlvbiBpKG8sQil7aWYoIXMuaXNVbmRlZmluZWQoQikpcmV0dXJuIEkodm9pZCAwLEIpfWZ1bmN0aW9uIGcobyxCKXtpZihzLmlzVW5kZWZpbmVkKEIpKXtpZighcy5pc1VuZGVmaW5lZChvKSlyZXR1cm4gSSh2b2lkIDAsbyl9ZWxzZSByZXR1cm4gSSh2b2lkIDAsQil9ZnVuY3Rpb24gbihvLEIsYyl7aWYoYyBpbiBlKXJldHVybiBJKG8sQik7aWYoYyBpbiBBKXJldHVybiBJKHZvaWQgMCxvKX1sZXQgRT17dXJsOmksbWV0aG9kOmksZGF0YTppLGJhc2VVUkw6Zyx0cmFuc2Zvcm1SZXF1ZXN0OmcsdHJhbnNmb3JtUmVzcG9uc2U6ZyxwYXJhbXNTZXJpYWxpemVyOmcsdGltZW91dDpnLHRpbWVvdXRNZXNzYWdlOmcsd2l0aENyZWRlbnRpYWxzOmcsYWRhcHRlcjpnLHJlc3BvbnNlVHlwZTpnLHhzcmZDb29raWVOYW1lOmcseHNyZkhlYWRlck5hbWU6ZyxvblVwbG9hZFByb2dyZXNzOmcsb25Eb3dubG9hZFByb2dyZXNzOmcsZGVjb21wcmVzczpnLG1heENvbnRlbnRMZW5ndGg6ZyxtYXhCb2R5TGVuZ3RoOmcsYmVmb3JlUmVkaXJlY3Q6Zyx0cmFuc3BvcnQ6ZyxodHRwQWdlbnQ6ZyxodHRwc0FnZW50OmcsY2FuY2VsVG9rZW46Zyxzb2NrZXRQYXRoOmcscmVzcG9uc2VFbmNvZGluZzpnLHZhbGlkYXRlU3RhdHVzOm4saGVhZGVyczoobyxCKT0+cih6ZShvKSx6ZShCKSwhMCl9O3JldHVybiBzLmZvckVhY2goT2JqZWN0LmtleXMoT2JqZWN0LmFzc2lnbih7fSxBLGUpKSxmdW5jdGlvbihCKXtsZXQgYz1FW0JdfHxyLGE9YyhBW0JdLGVbQl0sQik7cy5pc1VuZGVmaW5lZChhKSYmYyE9PW58fCh0W0JdPWEpfSksdH12YXIgU0E9IjEuNC4wIjt2YXIgdkE9e307WyJvYmplY3QiLCJib29sZWFuIiwibnVtYmVyIiwiZnVuY3Rpb24iLCJzdHJpbmciLCJzeW1ib2wiXS5mb3JFYWNoKChBLGUpPT57dkFbQV09ZnVuY3Rpb24oSSl7cmV0dXJuIHR5cGVvZiBJPT09QXx8ImEiKyhlPDE/Im4gIjoiICIpK0F9fSk7dmFyIFhlPXt9O3ZBLnRyYW5zaXRpb25hbD1mdW5jdGlvbihlLHQsSSl7ZnVuY3Rpb24gcihpLGcpe3JldHVybiJbQXhpb3MgdiIrU0ErIl0gVHJhbnNpdGlvbmFsIG9wdGlvbiBcJyIraSsiXCciK2crKEk/Ii4gIitJOiIiKX1yZXR1cm4oaSxnLG4pPT57aWYoZT09PSExKXRocm93IG5ldyBsKHIoZywiIGhhcyBiZWVuIHJlbW92ZWQiKyh0PyIgaW4gIit0OiIiKSksbC5FUlJfREVQUkVDQVRFRCk7cmV0dXJuIHQmJiFYZVtnXSYmKFhlW2ddPSEwLGNvbnNvbGUud2FybihyKGcsIiBoYXMgYmVlbiBkZXByZWNhdGVkIHNpbmNlIHYiK3QrIiBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHRoZSBuZWFyIGZ1dHVyZSIpKSksZT9lKGksZyxuKTohMH19O2Z1bmN0aW9uIG1JKEEsZSx0KXtpZih0eXBlb2YgQSE9Im9iamVjdCIpdGhyb3cgbmV3IGwoIm9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QiLGwuRVJSX0JBRF9PUFRJT05fVkFMVUUpO2xldCBJPU9iamVjdC5rZXlzKEEpLHI9SS5sZW5ndGg7Zm9yKDtyLS0gPjA7KXtsZXQgaT1JW3JdLGc9ZVtpXTtpZihnKXtsZXQgbj1BW2ldLEU9bj09PXZvaWQgMHx8ZyhuLGksQSk7aWYoRSE9PSEwKXRocm93IG5ldyBsKCJvcHRpb24gIitpKyIgbXVzdCBiZSAiK0UsbC5FUlJfQkFEX09QVElPTl9WQUxVRSk7Y29udGludWV9aWYodCE9PSEwKXRocm93IG5ldyBsKCJVbmtub3duIG9wdGlvbiAiK2ksbC5FUlJfQkFEX09QVElPTil9fXZhciBOQT17YXNzZXJ0T3B0aW9uczptSSx2YWxpZGF0b3JzOnZBfTt2YXIgYj1OQS52YWxpZGF0b3JzLF89Y2xhc3N7Y29uc3RydWN0b3IoZSl7dGhpcy5kZWZhdWx0cz1lLHRoaXMuaW50ZXJjZXB0b3JzPXtyZXF1ZXN0Om5ldyBQQSxyZXNwb25zZTpuZXcgUEF9fXJlcXVlc3QoZSx0KXt0eXBlb2YgZT09InN0cmluZyI/KHQ9dHx8e30sdC51cmw9ZSk6dD1lfHx7fSx0PWsodGhpcy5kZWZhdWx0cyx0KTtsZXR7dHJhbnNpdGlvbmFsOkkscGFyYW1zU2VyaWFsaXplcjpyLGhlYWRlcnM6aX09dDtJIT09dm9pZCAwJiZOQS5hc3NlcnRPcHRpb25zKEkse3NpbGVudEpTT05QYXJzaW5nOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbiksZm9yY2VkSlNPTlBhcnNpbmc6Yi50cmFuc2l0aW9uYWwoYi5ib29sZWFuKSxjbGFyaWZ5VGltZW91dEVycm9yOmIudHJhbnNpdGlvbmFsKGIuYm9vbGVhbil9LCExKSxyIT1udWxsJiYocy5pc0Z1bmN0aW9uKHIpP3QucGFyYW1zU2VyaWFsaXplcj17c2VyaWFsaXplOnJ9Ok5BLmFzc2VydE9wdGlvbnMocix7ZW5jb2RlOmIuZnVuY3Rpb24sc2VyaWFsaXplOmIuZnVuY3Rpb259LCEwKSksdC5tZXRob2Q9KHQubWV0aG9kfHx0aGlzLmRlZmF1bHRzLm1ldGhvZHx8ImdldCIpLnRvTG93ZXJDYXNlKCk7bGV0IGc7Zz1pJiZzLm1lcmdlKGkuY29tbW9uLGlbdC5tZXRob2RdKSxnJiZzLmZvckVhY2goWyJkZWxldGUiLCJnZXQiLCJoZWFkIiwicG9zdCIsInB1dCIsInBhdGNoIiwiY29tbW9uIl0sUT0+e2RlbGV0ZSBpW1FdfSksdC5oZWFkZXJzPXAuY29uY2F0KGcsaSk7bGV0IG49W10sRT0hMDt0aGlzLmludGVyY2VwdG9ycy5yZXF1ZXN0LmZvckVhY2goZnVuY3Rpb24oZil7dHlwZW9mIGYucnVuV2hlbj09ImZ1bmN0aW9uIiYmZi5ydW5XaGVuKHQpPT09ITF8fChFPUUmJmYuc3luY2hyb25vdXMsbi51bnNoaWZ0KGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpKX0pO2xldCBvPVtdO3RoaXMuaW50ZXJjZXB0b3JzLnJlc3BvbnNlLmZvckVhY2goZnVuY3Rpb24oZil7by5wdXNoKGYuZnVsZmlsbGVkLGYucmVqZWN0ZWQpfSk7bGV0IEIsYz0wLGE7aWYoIUUpe2xldCBRPVtGQS5iaW5kKHRoaXMpLHZvaWQgMF07Zm9yKFEudW5zaGlmdC5hcHBseShRLG4pLFEucHVzaC5hcHBseShRLG8pLGE9US5sZW5ndGgsQj1Qcm9taXNlLnJlc29sdmUodCk7YzxhOylCPUIudGhlbihRW2MrK10sUVtjKytdKTtyZXR1cm4gQn1hPW4ubGVuZ3RoO2xldCBDPXQ7Zm9yKGM9MDtjPGE7KXtsZXQgUT1uW2MrK10sZj1uW2MrK107dHJ5e0M9UShDKX1jYXRjaChtKXtmLmNhbGwodGhpcyxtKTticmVha319dHJ5e0I9RkEuY2FsbCh0aGlzLEMpfWNhdGNoKFEpe3JldHVybiBQcm9taXNlLnJlamVjdChRKX1mb3IoYz0wLGE9by5sZW5ndGg7YzxhOylCPUIudGhlbihvW2MrK10sb1tjKytdKTtyZXR1cm4gQn1nZXRVcmkoZSl7ZT1rKHRoaXMuZGVmYXVsdHMsZSk7bGV0IHQ9ckEoZS5iYXNlVVJMLGUudXJsKTtyZXR1cm4gQUEodCxlLnBhcmFtcyxlLnBhcmFtc1NlcmlhbGl6ZXIpfX07cy5mb3JFYWNoKFsiZGVsZXRlIiwiZ2V0IiwiaGVhZCIsIm9wdGlvbnMiXSxmdW5jdGlvbihlKXtfLnByb3RvdHlwZVtlXT1mdW5jdGlvbih0LEkpe3JldHVybiB0aGlzLnJlcXVlc3QoayhJfHx7fSx7bWV0aG9kOmUsdXJsOnQsZGF0YTooSXx8e30pLmRhdGF9KSl9fSk7cy5mb3JFYWNoKFsicG9zdCIsInB1dCIsInBhdGNoIl0sZnVuY3Rpb24oZSl7ZnVuY3Rpb24gdChJKXtyZXR1cm4gZnVuY3Rpb24oaSxnLG4pe3JldHVybiB0aGlzLnJlcXVlc3QoayhufHx7fSx7bWV0aG9kOmUsaGVhZGVyczpJP3siQ29udGVudC1UeXBlIjoibXVsdGlwYXJ0L2Zvcm0tZGF0YSJ9Ont9LHVybDppLGRhdGE6Z30pKX19Xy5wcm90b3R5cGVbZV09dCgpLF8ucHJvdG90eXBlW2UrIkZvcm0iXT10KCEwKX0pO3ZhciBpQT1fO3ZhciAkQT1jbGFzcyBBe2NvbnN0cnVjdG9yKGUpe2lmKHR5cGVvZiBlIT0iZnVuY3Rpb24iKXRocm93IG5ldyBUeXBlRXJyb3IoImV4ZWN1dG9yIG11c3QgYmUgYSBmdW5jdGlvbi4iKTtsZXQgdDt0aGlzLnByb21pc2U9bmV3IFByb21pc2UoZnVuY3Rpb24oaSl7dD1pfSk7bGV0IEk9dGhpczt0aGlzLnByb21pc2UudGhlbihyPT57aWYoIUkuX2xpc3RlbmVycylyZXR1cm47bGV0IGk9SS5fbGlzdGVuZXJzLmxlbmd0aDtmb3IoO2ktLSA+MDspSS5fbGlzdGVuZXJzW2ldKHIpO0kuX2xpc3RlbmVycz1udWxsfSksdGhpcy5wcm9taXNlLnRoZW49cj0+e2xldCBpLGc9bmV3IFByb21pc2Uobj0+e0kuc3Vic2NyaWJlKG4pLGk9bn0pLnRoZW4ocik7cmV0dXJuIGcuY2FuY2VsPWZ1bmN0aW9uKCl7SS51bnN1YnNjcmliZShpKX0sZ30sZShmdW5jdGlvbihpLGcsbil7SS5yZWFzb258fChJLnJlYXNvbj1uZXcgTShpLGcsbiksdChJLnJlYXNvbikpfSl9dGhyb3dJZlJlcXVlc3RlZCgpe2lmKHRoaXMucmVhc29uKXRocm93IHRoaXMucmVhc29ufXN1YnNjcmliZShlKXtpZih0aGlzLnJlYXNvbil7ZSh0aGlzLnJlYXNvbik7cmV0dXJufXRoaXMuX2xpc3RlbmVycz90aGlzLl9saXN0ZW5lcnMucHVzaChlKTp0aGlzLl9saXN0ZW5lcnM9W2VdfXVuc3Vic2NyaWJlKGUpe2lmKCF0aGlzLl9saXN0ZW5lcnMpcmV0dXJuO2xldCB0PXRoaXMuX2xpc3RlbmVycy5pbmRleE9mKGUpO3QhPT0tMSYmdGhpcy5fbGlzdGVuZXJzLnNwbGljZSh0LDEpfXN0YXRpYyBzb3VyY2UoKXtsZXQgZTtyZXR1cm57dG9rZW46bmV3IEEoZnVuY3Rpb24ocil7ZT1yfSksY2FuY2VsOmV9fX0sdmU9JEE7ZnVuY3Rpb24gQWUoQSl7cmV0dXJuIGZ1bmN0aW9uKHQpe3JldHVybiBBLmFwcGx5KG51bGwsdCl9fWZ1bmN0aW9uIGVlKEEpe3JldHVybiBzLmlzT2JqZWN0KEEpJiZBLmlzQXhpb3NFcnJvcj09PSEwfXZhciB0ZT17Q29udGludWU6MTAwLFN3aXRjaGluZ1Byb3RvY29sczoxMDEsUHJvY2Vzc2luZzoxMDIsRWFybHlIaW50czoxMDMsT2s6MjAwLENyZWF0ZWQ6MjAxLEFjY2VwdGVkOjIwMixOb25BdXRob3JpdGF0aXZlSW5mb3JtYXRpb246MjAzLE5vQ29udGVudDoyMDQsUmVzZXRDb250ZW50OjIwNSxQYXJ0aWFsQ29udGVudDoyMDYsTXVsdGlTdGF0dXM6MjA3LEFscmVhZHlSZXBvcnRlZDoyMDgsSW1Vc2VkOjIyNixNdWx0aXBsZUNob2ljZXM6MzAwLE1vdmVkUGVybWFuZW50bHk6MzAxLEZvdW5kOjMwMixTZWVPdGhlcjozMDMsTm90TW9kaWZpZWQ6MzA0LFVzZVByb3h5OjMwNSxVbnVzZWQ6MzA2LFRlbXBvcmFyeVJlZGlyZWN0OjMwNyxQZXJtYW5lbnRSZWRpcmVjdDozMDgsQmFkUmVxdWVzdDo0MDAsVW5hdXRob3JpemVkOjQwMSxQYXltZW50UmVxdWlyZWQ6NDAyLEZvcmJpZGRlbjo0MDMsTm90Rm91bmQ6NDA0LE1ldGhvZE5vdEFsbG93ZWQ6NDA1LE5vdEFjY2VwdGFibGU6NDA2LFByb3h5QXV0aGVudGljYXRpb25SZXF1aXJlZDo0MDcsUmVxdWVzdFRpbWVvdXQ6NDA4LENvbmZsaWN0OjQwOSxHb25lOjQxMCxMZW5ndGhSZXF1aXJlZDo0MTEsUHJlY29uZGl0aW9uRmFpbGVkOjQxMixQYXlsb2FkVG9vTGFyZ2U6NDEzLFVyaVRvb0xvbmc6NDE0LFVuc3VwcG9ydGVkTWVkaWFUeXBlOjQxNSxSYW5nZU5vdFNhdGlzZmlhYmxlOjQxNixFeHBlY3RhdGlvbkZhaWxlZDo0MTcsSW1BVGVhcG90OjQxOCxNaXNkaXJlY3RlZFJlcXVlc3Q6NDIxLFVucHJvY2Vzc2FibGVFbnRpdHk6NDIyLExvY2tlZDo0MjMsRmFpbGVkRGVwZW5kZW5jeTo0MjQsVG9vRWFybHk6NDI1LFVwZ3JhZGVSZXF1aXJlZDo0MjYsUHJlY29uZGl0aW9uUmVxdWlyZWQ6NDI4LFRvb01hbnlSZXF1ZXN0czo0MjksUmVxdWVzdEhlYWRlckZpZWxkc1Rvb0xhcmdlOjQzMSxVbmF2YWlsYWJsZUZvckxlZ2FsUmVhc29uczo0NTEsSW50ZXJuYWxTZXJ2ZXJFcnJvcjo1MDAsTm90SW1wbGVtZW50ZWQ6NTAxLEJhZEdhdGV3YXk6NTAyLFNlcnZpY2VVbmF2YWlsYWJsZTo1MDMsR2F0ZXdheVRpbWVvdXQ6NTA0LEh0dHBWZXJzaW9uTm90U3VwcG9ydGVkOjUwNSxWYXJpYW50QWxzb05lZ290aWF0ZXM6NTA2LEluc3VmZmljaWVudFN0b3JhZ2U6NTA3LExvb3BEZXRlY3RlZDo1MDgsTm90RXh0ZW5kZWQ6NTEwLE5ldHdvcmtBdXRoZW50aWNhdGlvblJlcXVpcmVkOjUxMX07T2JqZWN0LmVudHJpZXModGUpLmZvckVhY2goKFtBLGVdKT0+e3RlW2VdPUF9KTt2YXIgJGU9dGU7ZnVuY3Rpb24gQXQoQSl7bGV0IGU9bmV3IGlBKEEpLHQ9WChpQS5wcm90b3R5cGUucmVxdWVzdCxlKTtyZXR1cm4gcy5leHRlbmQodCxpQS5wcm90b3R5cGUsZSx7YWxsT3duS2V5czohMH0pLHMuZXh0ZW5kKHQsZSxudWxsLHthbGxPd25LZXlzOiEwfSksdC5jcmVhdGU9ZnVuY3Rpb24ocil7cmV0dXJuIEF0KGsoQSxyKSl9LHR9dmFyIGg9QXQoaik7aC5BeGlvcz1pQTtoLkNhbmNlbGVkRXJyb3I9TTtoLkNhbmNlbFRva2VuPXZlO2guaXNDYW5jZWw9SUE7aC5WRVJTSU9OPVNBO2gudG9Gb3JtRGF0YT1KO2guQXhpb3NFcnJvcj1sO2guQ2FuY2VsPWguQ2FuY2VsZWRFcnJvcjtoLmFsbD1mdW5jdGlvbihlKXtyZXR1cm4gUHJvbWlzZS5hbGwoZSl9O2guc3ByZWFkPUFlO2guaXNBeGlvc0Vycm9yPWVlO2gubWVyZ2VDb25maWc9aztoLkF4aW9zSGVhZGVycz1wO2guZm9ybVRvSlNPTj1BPT5EQShzLmlzSFRNTEZvcm0oQSk/bmV3IEZvcm1EYXRhKEEpOkEpO2guSHR0cFN0YXR1c0NvZGU9JGU7aC5kZWZhdWx0PWg7dmFyIFJBPWg7dmFye0F4aW9zOlNnLEF4aW9zRXJyb3I6TmcsQ2FuY2VsZWRFcnJvcjpSZyxpc0NhbmNlbDpHZyxDYW5jZWxUb2tlbjpVZyxWRVJTSU9OOmtnLGFsbDpMZyxDYW5jZWw6T2csaXNBeGlvc0Vycm9yOkpnLHNwcmVhZDpNZyx0b0Zvcm1EYXRhOmJnLEF4aW9zSGVhZGVyczpIZyxIdHRwU3RhdHVzQ29kZTpZZyxmb3JtVG9KU09OOnFnLG1lcmdlQ29uZmlnOlRnfT1SQTt2YXIgZ0EsTCxyZSxJZT17ZW52OntlbXNjcmlwdGVuX25vdGlmeV9tZW1vcnlfZ3Jvd3RoOmZ1bmN0aW9uKEEpe3JlPW5ldyBVaW50OEFycmF5KEwuZXhwb3J0cy5tZW1vcnkuYnVmZmVyKX19fSxHQT1jbGFzc3tpbml0KCl7cmV0dXJuIGdBfHwodHlwZW9mIGZldGNoPCJ1Ij9nQT1mZXRjaCgiZGF0YTphcHBsaWNhdGlvbi93YXNtO2Jhc2U2NCwiK2V0KS50aGVuKGU9PmUuYXJyYXlCdWZmZXIoKSkudGhlbihlPT5XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShlLEllKSkudGhlbih0aGlzLl9pbml0KTpnQT1XZWJBc3NlbWJseS5pbnN0YW50aWF0ZShCdWZmZXIuZnJvbShldCwiYmFzZTY0IiksSWUpLnRoZW4odGhpcy5faW5pdCksZ0EpfV9pbml0KGUpe0w9ZS5pbnN0YW5jZSxJZS5lbnYuZW1zY3JpcHRlbl9ub3RpZnlfbWVtb3J5X2dyb3d0aCgwKX1kZWNvZGUoZSx0PTApe2lmKCFMKXRocm93IG5ldyBFcnJvcigiWlNURERlY29kZXI6IEF3YWl0IC5pbml0KCkgYmVmb3JlIGRlY29kaW5nLiIpO2xldCBJPWUuYnl0ZUxlbmd0aCxyPUwuZXhwb3J0cy5tYWxsb2MoSSk7cmUuc2V0KGUsciksdD10fHxOdW1iZXIoTC5leHBvcnRzLlpTVERfZmluZERlY29tcHJlc3NlZFNpemUocixJKSk7bGV0IGk9TC5leHBvcnRzLm1hbGxvYyh0KSxnPUwuZXhwb3J0cy5aU1REX2RlY29tcHJlc3MoaSx0LHIsSSksbj1yZS5zbGljZShpLGkrZyk7cmV0dXJuIEwuZXhwb3J0cy5mcmVlKHIpLEwuZXhwb3J0cy5mcmVlKGkpLG59fSxldD0iQUdGemJRRUFBQUFCYmc1Z0EzOS9md0YvWUFGL0FYOWdBbjkvQUdBQmZ3QmdCWDkvZjM5L0FYOWdBMzkvZndCZ0JIOS9mMzhCZjJBQUFYOWdBbjkvQVg5Z0IzOS9mMzkvZjM4QmYyQUNmMzhCZm1BSWYzOS9mMzkvZjM4QmYyQUZmMzkvZjM4QVlBNS9mMzkvZjM5L2YzOS9mMzkvZndGL0FpY0JBMlZ1ZGg5bGJYTmpjbWx3ZEdWdVgyNXZkR2xtZVY5dFpXMXZjbmxmWjNKdmQzUm9BQU1ESXlJSEFBQUJBUU1IQXdFQUNRUUFCUUVJQ0FFRkJnUUVCQU1HQUFBS0FBVUxEQTBHQkFVQmNBRUJBUVVIQVFHQUFvQ0FBZ1lJQVg4QlFZQ2pCQXNIcmdFTEJtMWxiVzl5ZVFJQUJtMWhiR3h2WXdBRkJHWnlaV1VBQmd4YVUxUkVYMmx6UlhKeWIzSUFFaGxhVTFSRVgyWnBibVJFWldOdmJYQnlaWE56WldSVGFYcGxBQndQV2xOVVJGOWtaV052YlhCeVpYTnpBQ0laWDE5cGJtUnBjbVZqZEY5bWRXNWpkR2x2Ymw5MFlXSnNaUUVBRUY5ZlpYSnlibTlmYkc5allYUnBiMjRBQVFsemRHRmphMU5oZG1VQUJ3eHpkR0ZqYTFKbGMzUnZjbVVBQ0FwemRHRmphMEZzYkc5akFBa0tpL0lCSWdVQVFZUWZDek1CQVg4Z0FnUkFJQUFoQXdOQUlBTWdBUzBBQURvQUFDQURRUUZxSVFNZ0FVRUJhaUVCSUFKQkFXc2lBZzBBQ3dzZ0FBc3BBUUYvSUFJRVFDQUFJUU1EUUNBRElBRTZBQUFnQTBFQmFpRURJQUpCQVdzaUFnMEFDd3NnQUF0c0FRSi9RWUFmS0FJQUlnRWdBRUVIYWtGNGNTSUNhaUVBQWtBZ0FrRUFJQUFnQVUwYkRRQWdBRDhBUVJCMFN3UkFJQUEvQUVFUWRHdEIvLzhEYWtFUWRrQUFRWDlHQkg5QkFBVkJBQkFBUVFFTFJRMEJDMEdBSHlBQU5nSUFJQUVQQzBHRUgwRXdOZ0lBUVg4THVTY0JDMzhqQUVFUWF5SUtKQUFDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQUpBSUFCQjlBRk5CRUJCaUI4b0FnQWlCa0VRSUFCQkMycEJlSEVnQUVFTFNSc2lCVUVEZGlJQWRpSUJRUU54QkVBQ1FDQUJRWDl6UVFGeElBQnFJZ0pCQTNRaUFVR3dIMm9pQUNBQlFiZ2ZhaWdDQUNJQktBSUlJZ1JHQkVCQmlCOGdCa0YrSUFKM2NUWUNBQXdCQ3lBRUlBQTJBZ3dnQUNBRU5nSUlDeUFCUVFocUlRQWdBU0FDUVFOMElnSkJBM0kyQWdRZ0FTQUNhaUlCSUFFb0FnUkJBWEkyQWdRTUR3c2dCVUdRSHlnQ0FDSUhUUTBCSUFFRVFBSkFRUUlnQUhRaUFrRUFJQUpyY2lBQklBQjBjV2dpQVVFRGRDSUFRYkFmYWlJQ0lBQkJ1QjlxS0FJQUlnQW9BZ2dpQkVZRVFFR0lIeUFHUVg0Z0FYZHhJZ1kyQWdBTUFRc2dCQ0FDTmdJTUlBSWdCRFlDQ0FzZ0FDQUZRUU55TmdJRUlBQWdCV29pQ0NBQlFRTjBJZ0VnQldzaUJFRUJjallDQkNBQUlBRnFJQVEyQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUZCbkI4b0FnQWhBZ0ovSUFaQkFTQUhRUU4yZENJRGNVVUVRRUdJSHlBRElBWnlOZ0lBSUFFTUFRc2dBU2dDQ0FzaEF5QUJJQUkyQWdnZ0F5QUNOZ0lNSUFJZ0FUWUNEQ0FDSUFNMkFnZ0xJQUJCQ0dvaEFFR2NIeUFJTmdJQVFaQWZJQVEyQWdBTUR3dEJqQjhvQWdBaUMwVU5BU0FMYUVFQ2RFRzRJV29vQWdBaUFpZ0NCRUY0Y1NBRmF5RURJQUloQVFOQUFrQWdBU2dDRUNJQVJRUkFJQUVvQWhRaUFFVU5BUXNnQUNnQ0JFRjRjU0FGYXlJQklBTWdBU0FEU1NJQkd5RURJQUFnQWlBQkd5RUNJQUFoQVF3QkN3c2dBaWdDR0NFSklBSWdBaWdDRENJRVJ3UkFRWmdmS0FJQUdpQUNLQUlJSWdBZ0JEWUNEQ0FFSUFBMkFnZ01EZ3NnQWtFVWFpSUJLQUlBSWdCRkJFQWdBaWdDRUNJQVJRMERJQUpCRUdvaEFRc0RRQ0FCSVFnZ0FDSUVRUlJxSWdFb0FnQWlBQTBBSUFSQkVHb2hBU0FFS0FJUUlnQU5BQXNnQ0VFQU5nSUFEQTBMUVg4aEJTQUFRYjkvU3cwQUlBQkJDMm9pQUVGNGNTRUZRWXdmS0FJQUlnaEZEUUJCQUNBRmF5RURBa0FDUUFKQUFuOUJBQ0FGUVlBQ1NRMEFHa0VmSUFWQi8vLy9CMHNOQUJvZ0JVRW1JQUJCQ0habklnQnJka0VCY1NBQVFRRjBhMEUrYWdzaUIwRUNkRUc0SVdvb0FnQWlBVVVFUUVFQUlRQU1BUXRCQUNFQUlBVkJHU0FIUVFGMmEwRUFJQWRCSDBjYmRDRUNBMEFDUUNBQktBSUVRWGh4SUFWcklnWWdBMDhOQUNBQklRUWdCaUlERFFCQkFDRURJQUVoQUF3REN5QUFJQUVvQWhRaUJpQUdJQUVnQWtFZGRrRUVjV29vQWhBaUFVWWJJQUFnQmhzaEFDQUNRUUYwSVFJZ0FRMEFDd3NnQUNBRWNrVUVRRUVBSVFSQkFpQUhkQ0lBUVFBZ0FHdHlJQWh4SWdCRkRRTWdBR2hCQW5SQnVDRnFLQUlBSVFBTElBQkZEUUVMQTBBZ0FDZ0NCRUY0Y1NBRmF5SUNJQU5KSVFFZ0FpQURJQUViSVFNZ0FDQUVJQUViSVFRZ0FDZ0NFQ0lCQkg4Z0FRVWdBQ2dDRkFzaUFBMEFDd3NnQkVVTkFDQURRWkFmS0FJQUlBVnJUdzBBSUFRb0FoZ2hCeUFFSUFRb0Fnd2lBa2NFUUVHWUh5Z0NBQm9nQkNnQ0NDSUFJQUkyQWd3Z0FpQUFOZ0lJREF3TElBUkJGR29pQVNnQ0FDSUFSUVJBSUFRb0FoQWlBRVVOQXlBRVFSQnFJUUVMQTBBZ0FTRUdJQUFpQWtFVWFpSUJLQUlBSWdBTkFDQUNRUkJxSVFFZ0FpZ0NFQ0lBRFFBTElBWkJBRFlDQUF3TEN5QUZRWkFmS0FJQUlnUk5CRUJCbkI4b0FnQWhBQUpBSUFRZ0JXc2lBVUVRVHdSQUlBQWdCV29pQWlBQlFRRnlOZ0lFSUFBZ0JHb2dBVFlDQUNBQUlBVkJBM0kyQWdRTUFRc2dBQ0FFUVFOeU5nSUVJQUFnQkdvaUFTQUJLQUlFUVFGeU5nSUVRUUFoQWtFQUlRRUxRWkFmSUFFMkFnQkJuQjhnQWpZQ0FDQUFRUWhxSVFBTURRc2dCVUdVSHlnQ0FDSUNTUVJBUVpRZklBSWdCV3NpQVRZQ0FFR2dIMEdnSHlnQ0FDSUFJQVZxSWdJMkFnQWdBaUFCUVFGeU5nSUVJQUFnQlVFRGNqWUNCQ0FBUVFocUlRQU1EUXRCQUNFQUlBVkJMMm9pQXdKL1FlQWlLQUlBQkVCQjZDSW9BZ0FNQVF0QjdDSkNmemNDQUVIa0lrS0FvSUNBZ0lBRU53SUFRZUFpSUFwQkRHcEJjSEZCMktyVnFnVnpOZ0lBUWZRaVFRQTJBZ0JCeENKQkFEWUNBRUdBSUFzaUFXb2lCa0VBSUFGcklnaHhJZ0VnQlUwTkRFSEFJaWdDQUNJRUJFQkJ1Q0lvQWdBaUJ5QUJhaUlKSUFkTklBUWdDVWx5RFEwTEFrQkJ4Q0l0QUFCQkJIRkZCRUFDUUFKQUFrQUNRRUdnSHlnQ0FDSUVCRUJCeUNJaEFBTkFJQVFnQUNnQ0FDSUhUd1JBSUFjZ0FDZ0NCR29nQkVzTkF3c2dBQ2dDQ0NJQURRQUxDMEVBRUFRaUFrRi9SZzBESUFFaEJrSGtJaWdDQUNJQVFRRnJJZ1FnQW5FRVFDQUJJQUpySUFJZ0JHcEJBQ0FBYTNGcUlRWUxJQVVnQms4TkEwSEFJaWdDQUNJQUJFQkJ1Q0lvQWdBaUJDQUdhaUlJSUFSTklBQWdDRWx5RFFRTElBWVFCQ0lBSUFKSERRRU1CUXNnQmlBQ2F5QUljU0lHRUFRaUFpQUFLQUlBSUFBb0FnUnFSZzBCSUFJaEFBc2dBRUYvUmcwQklBVkJNR29nQmswRVFDQUFJUUlNQkF0QjZDSW9BZ0FpQWlBRElBWnJha0VBSUFKcmNTSUNFQVJCZjBZTkFTQUNJQVpxSVFZZ0FDRUNEQU1MSUFKQmYwY05BZ3RCeENKQnhDSW9BZ0JCQkhJMkFnQUxJQUVRQkNJQ1FYOUdRUUFRQkNJQVFYOUdjaUFBSUFKTmNnMEZJQUFnQW1zaUJpQUZRU2hxVFEwRkMwRzRJa0c0SWlnQ0FDQUdhaUlBTmdJQVFid2lLQUlBSUFCSkJFQkJ2Q0lnQURZQ0FBc0NRRUdnSHlnQ0FDSURCRUJCeUNJaEFBTkFJQUlnQUNnQ0FDSUJJQUFvQWdRaUJHcEdEUUlnQUNnQ0NDSUFEUUFMREFRTFFaZ2ZLQUlBSWdCQkFDQUFJQUpORzBVRVFFR1lIeUFDTmdJQUMwRUFJUUJCekNJZ0JqWUNBRUhJSWlBQ05nSUFRYWdmUVg4MkFnQkJyQjlCNENJb0FnQTJBZ0JCMUNKQkFEWUNBQU5BSUFCQkEzUWlBVUc0SDJvZ0FVR3dIMm9pQkRZQ0FDQUJRYndmYWlBRU5nSUFJQUJCQVdvaUFFRWdSdzBBQzBHVUh5QUdRU2hySWdCQmVDQUNhMEVIY1NJQmF5SUVOZ0lBUWFBZklBRWdBbW9pQVRZQ0FDQUJJQVJCQVhJMkFnUWdBQ0FDYWtFb05nSUVRYVFmUWZBaUtBSUFOZ0lBREFRTElBSWdBMDBnQVNBRFMzSU5BaUFBS0FJTVFRaHhEUUlnQUNBRUlBWnFOZ0lFUWFBZklBTkJlQ0FEYTBFSGNTSUFhaUlCTmdJQVFaUWZRWlFmS0FJQUlBWnFJZ0lnQUdzaUFEWUNBQ0FCSUFCQkFYSTJBZ1FnQWlBRGFrRW9OZ0lFUWFRZlFmQWlLQUlBTmdJQURBTUxRUUFoQkF3S0MwRUFJUUlNQ0F0Qm1COG9BZ0FnQWtzRVFFR1lIeUFDTmdJQUN5QUNJQVpxSVFGQnlDSWhBQUpBQWtBQ1FBTkFJQUVnQUNnQ0FFY0VRQ0FBS0FJSUlnQU5BUXdDQ3dzZ0FDMEFERUVJY1VVTkFRdEJ5Q0loQUFOQUlBTWdBQ2dDQUNJQlR3UkFJQUVnQUNnQ0JHb2lCQ0FEU3cwREN5QUFLQUlJSVFBTUFBc0FDeUFBSUFJMkFnQWdBQ0FBS0FJRUlBWnFOZ0lFSUFKQmVDQUNhMEVIY1dvaUJ5QUZRUU55TmdJRUlBRkJlQ0FCYTBFSGNXb2lCaUFGSUFkcUlnVnJJUUFnQXlBR1JnUkFRYUFmSUFVMkFnQkJsQjlCbEI4b0FnQWdBR29pQURZQ0FDQUZJQUJCQVhJMkFnUU1DQXRCbkI4b0FnQWdCa1lFUUVHY0h5QUZOZ0lBUVpBZlFaQWZLQUlBSUFCcUlnQTJBZ0FnQlNBQVFRRnlOZ0lFSUFBZ0JXb2dBRFlDQUF3SUN5QUdLQUlFSWdOQkEzRkJBVWNOQmlBRFFYaHhJUWtnQTBIL0FVMEVRQ0FHS0FJTUlnRWdCaWdDQ0NJQ1JnUkFRWWdmUVlnZktBSUFRWDRnQTBFRGRuZHhOZ0lBREFjTElBSWdBVFlDRENBQklBSTJBZ2dNQmdzZ0JpZ0NHQ0VJSUFZZ0JpZ0NEQ0lDUndSQUlBWW9BZ2dpQVNBQ05nSU1JQUlnQVRZQ0NBd0ZDeUFHUVJScUlnRW9BZ0FpQTBVRVFDQUdLQUlRSWdORkRRUWdCa0VRYWlFQkN3TkFJQUVoQkNBRElnSkJGR29pQVNnQ0FDSUREUUFnQWtFUWFpRUJJQUlvQWhBaUF3MEFDeUFFUVFBMkFnQU1CQXRCbEI4Z0JrRW9heUlBUVhnZ0FtdEJCM0VpQVdzaUNEWUNBRUdnSHlBQklBSnFJZ0UyQWdBZ0FTQUlRUUZ5TmdJRUlBQWdBbXBCS0RZQ0JFR2tIMEh3SWlnQ0FEWUNBQ0FESUFSQkp5QUVhMEVIY1dwQkwyc2lBQ0FBSUFOQkVHcEpHeUlCUVJzMkFnUWdBVUhRSWlrQ0FEY0NFQ0FCUWNnaUtRSUFOd0lJUWRBaUlBRkJDR28yQWdCQnpDSWdCallDQUVISUlpQUNOZ0lBUWRRaVFRQTJBZ0FnQVVFWWFpRUFBMEFnQUVFSE5nSUVJQUJCQ0dvZ0FFRUVhaUVBSUFSSkRRQUxJQUVnQTBZTkFDQUJJQUVvQWdSQmZuRTJBZ1FnQXlBQklBTnJJZ0pCQVhJMkFnUWdBU0FDTmdJQUlBSkIvd0ZOQkVBZ0FrRjRjVUd3SDJvaEFBSi9RWWdmS0FJQUlnRkJBU0FDUVFOMmRDSUNjVVVFUUVHSUh5QUJJQUp5TmdJQUlBQU1BUXNnQUNnQ0NBc2hBU0FBSUFNMkFnZ2dBU0FETmdJTUlBTWdBRFlDRENBRElBRTJBZ2dNQVF0Qkh5RUFJQUpCLy8vL0IwMEVRQ0FDUVNZZ0FrRUlkbWNpQUd0MlFRRnhJQUJCQVhSclFUNXFJUUFMSUFNZ0FEWUNIQ0FEUWdBM0FoQWdBRUVDZEVHNElXb2hBUUpBQWtCQmpCOG9BZ0FpQkVFQklBQjBJZ1p4UlFSQVFZd2ZJQVFnQm5JMkFnQWdBU0FETmdJQURBRUxJQUpCR1NBQVFRRjJhMEVBSUFCQkgwY2JkQ0VBSUFFb0FnQWhCQU5BSUFRaUFTZ0NCRUY0Y1NBQ1JnMENJQUJCSFhZaEJDQUFRUUYwSVFBZ0FTQUVRUVJ4YWlJR0tBSVFJZ1FOQUFzZ0JpQUROZ0lRQ3lBRElBRTJBaGdnQXlBRE5nSU1JQU1nQXpZQ0NBd0JDeUFCS0FJSUlnQWdBellDRENBQklBTTJBZ2dnQTBFQU5nSVlJQU1nQVRZQ0RDQURJQUEyQWdnTFFaUWZLQUlBSWdBZ0JVME5BRUdVSHlBQUlBVnJJZ0UyQWdCQm9COUJvQjhvQWdBaUFDQUZhaUlDTmdJQUlBSWdBVUVCY2pZQ0JDQUFJQVZCQTNJMkFnUWdBRUVJYWlFQURBZ0xRWVFmUVRBMkFnQkJBQ0VBREFjTFFRQWhBZ3NnQ0VVTkFBSkFJQVlvQWh3aUFVRUNkRUc0SVdvaUJDZ0NBQ0FHUmdSQUlBUWdBallDQUNBQ0RRRkJqQjlCakI4b0FnQkJmaUFCZDNFMkFnQU1BZ3NnQ0VFUVFSUWdDQ2dDRUNBR1JodHFJQUkyQWdBZ0FrVU5BUXNnQWlBSU5nSVlJQVlvQWhBaUFRUkFJQUlnQVRZQ0VDQUJJQUkyQWhnTElBWW9BaFFpQVVVTkFDQUNJQUUyQWhRZ0FTQUNOZ0lZQ3lBQUlBbHFJUUFnQmlBSmFpSUdLQUlFSVFNTElBWWdBMEYrY1RZQ0JDQUZJQUJCQVhJMkFnUWdBQ0FGYWlBQU5nSUFJQUJCL3dGTkJFQWdBRUY0Y1VHd0gyb2hBUUovUVlnZktBSUFJZ0pCQVNBQVFRTjJkQ0lBY1VVRVFFR0lIeUFBSUFKeU5nSUFJQUVNQVFzZ0FTZ0NDQXNoQUNBQklBVTJBZ2dnQUNBRk5nSU1JQVVnQVRZQ0RDQUZJQUEyQWdnTUFRdEJIeUVESUFCQi8vLy9CMDBFUUNBQVFTWWdBRUVJZG1jaUFXdDJRUUZ4SUFGQkFYUnJRVDVxSVFNTElBVWdBellDSENBRlFnQTNBaEFnQTBFQ2RFRzRJV29oQVFKQUFrQkJqQjhvQWdBaUFrRUJJQU4wSWdSeFJRUkFRWXdmSUFJZ0JISTJBZ0FnQVNBRk5nSUFEQUVMSUFCQkdTQURRUUYyYTBFQUlBTkJIMGNiZENFRElBRW9BZ0FoQWdOQUlBSWlBU2dDQkVGNGNTQUFSZzBDSUFOQkhYWWhBaUFEUVFGMElRTWdBU0FDUVFSeGFpSUVLQUlRSWdJTkFBc2dCQ0FGTmdJUUN5QUZJQUUyQWhnZ0JTQUZOZ0lNSUFVZ0JUWUNDQXdCQ3lBQktBSUlJZ0FnQlRZQ0RDQUJJQVUyQWdnZ0JVRUFOZ0lZSUFVZ0FUWUNEQ0FGSUFBMkFnZ0xJQWRCQ0dvaEFBd0NDd0pBSUFkRkRRQUNRQ0FFS0FJY0lnQkJBblJCdUNGcUlnRW9BZ0FnQkVZRVFDQUJJQUkyQWdBZ0FnMEJRWXdmSUFoQmZpQUFkM0VpQ0RZQ0FBd0NDeUFIUVJCQkZDQUhLQUlRSUFSR0cyb2dBallDQUNBQ1JRMEJDeUFDSUFjMkFoZ2dCQ2dDRUNJQUJFQWdBaUFBTmdJUUlBQWdBallDR0FzZ0JDZ0NGQ0lBUlEwQUlBSWdBRFlDRkNBQUlBSTJBaGdMQWtBZ0EwRVBUUVJBSUFRZ0F5QUZhaUlBUVFOeU5nSUVJQUFnQkdvaUFDQUFLQUlFUVFGeU5nSUVEQUVMSUFRZ0JVRURjallDQkNBRUlBVnFJZ0lnQTBFQmNqWUNCQ0FDSUFOcUlBTTJBZ0FnQTBIL0FVMEVRQ0FEUVhoeFFiQWZhaUVBQW45QmlCOG9BZ0FpQVVFQklBTkJBM1owSWdOeFJRUkFRWWdmSUFFZ0EzSTJBZ0FnQUF3QkN5QUFLQUlJQ3lFQklBQWdBallDQ0NBQklBSTJBZ3dnQWlBQU5nSU1JQUlnQVRZQ0NBd0JDMEVmSVFBZ0EwSC8vLzhIVFFSQUlBTkJKaUFEUVFoMlp5SUFhM1pCQVhFZ0FFRUJkR3RCUG1vaEFBc2dBaUFBTmdJY0lBSkNBRGNDRUNBQVFRSjBRYmdoYWlFQkFrQUNRQ0FJUVFFZ0FIUWlCbkZGQkVCQmpCOGdCaUFJY2pZQ0FDQUJJQUkyQWdBTUFRc2dBMEVaSUFCQkFYWnJRUUFnQUVFZlJ4dDBJUUFnQVNnQ0FDRUZBMEFnQlNJQktBSUVRWGh4SUFOR0RRSWdBRUVkZGlFR0lBQkJBWFFoQUNBQklBWkJCSEZxSWdZb0FoQWlCUTBBQ3lBR0lBSTJBaEFMSUFJZ0FUWUNHQ0FDSUFJMkFnd2dBaUFDTmdJSURBRUxJQUVvQWdnaUFDQUNOZ0lNSUFFZ0FqWUNDQ0FDUVFBMkFoZ2dBaUFCTmdJTUlBSWdBRFlDQ0FzZ0JFRUlhaUVBREFFTEFrQWdDVVVOQUFKQUlBSW9BaHdpQUVFQ2RFRzRJV29pQVNnQ0FDQUNSZ1JBSUFFZ0JEWUNBQ0FFRFFGQmpCOGdDMEYrSUFCM2NUWUNBQXdDQ3lBSlFSQkJGQ0FKS0FJUUlBSkdHMm9nQkRZQ0FDQUVSUTBCQ3lBRUlBazJBaGdnQWlnQ0VDSUFCRUFnQkNBQU5nSVFJQUFnQkRZQ0dBc2dBaWdDRkNJQVJRMEFJQVFnQURZQ0ZDQUFJQVEyQWhnTEFrQWdBMEVQVFFSQUlBSWdBeUFGYWlJQVFRTnlOZ0lFSUFBZ0Ftb2lBQ0FBS0FJRVFRRnlOZ0lFREFFTElBSWdCVUVEY2pZQ0JDQUNJQVZxSWdRZ0EwRUJjallDQkNBRElBUnFJQU0yQWdBZ0J3UkFJQWRCZUhGQnNCOXFJUUJCbkI4b0FnQWhBUUovUVFFZ0IwRURkblFpQlNBR2NVVUVRRUdJSHlBRklBWnlOZ0lBSUFBTUFRc2dBQ2dDQ0FzaEJpQUFJQUUyQWdnZ0JpQUJOZ0lNSUFFZ0FEWUNEQ0FCSUFZMkFnZ0xRWndmSUFRMkFnQkJrQjhnQXpZQ0FBc2dBa0VJYWlFQUN5QUtRUkJxSkFBZ0FBdlNDd0VIZndKQUlBQkZEUUFnQUVFSWF5SUNJQUJCQkdzb0FnQWlBVUY0Y1NJQWFpRUZBa0FnQVVFQmNRMEFJQUZCQTNGRkRRRWdBaUFDS0FJQUlnRnJJZ0pCbUI4b0FnQkpEUUVnQUNBQmFpRUFBa0FDUUVHY0h5Z0NBQ0FDUndSQUlBRkIvd0ZOQkVBZ0FVRURkaUVFSUFJb0Fnd2lBU0FDS0FJSUlnTkdCRUJCaUI5QmlCOG9BZ0JCZmlBRWQzRTJBZ0FNQlFzZ0F5QUJOZ0lNSUFFZ0F6WUNDQXdFQ3lBQ0tBSVlJUVlnQWlBQ0tBSU1JZ0ZIQkVBZ0FpZ0NDQ0lESUFFMkFnd2dBU0FETmdJSURBTUxJQUpCRkdvaUJDZ0NBQ0lEUlFSQUlBSW9BaEFpQTBVTkFpQUNRUkJxSVFRTEEwQWdCQ0VISUFNaUFVRVVhaUlFS0FJQUlnTU5BQ0FCUVJCcUlRUWdBU2dDRUNJRERRQUxJQWRCQURZQ0FBd0NDeUFGS0FJRUlnRkJBM0ZCQTBjTkFrR1FIeUFBTmdJQUlBVWdBVUYrY1RZQ0JDQUNJQUJCQVhJMkFnUWdCU0FBTmdJQUR3dEJBQ0VCQ3lBR1JRMEFBa0FnQWlnQ0hDSURRUUowUWJnaGFpSUVLQUlBSUFKR0JFQWdCQ0FCTmdJQUlBRU5BVUdNSDBHTUh5Z0NBRUYrSUFOM2NUWUNBQXdDQ3lBR1FSQkJGQ0FHS0FJUUlBSkdHMm9nQVRZQ0FDQUJSUTBCQ3lBQklBWTJBaGdnQWlnQ0VDSURCRUFnQVNBRE5nSVFJQU1nQVRZQ0dBc2dBaWdDRkNJRFJRMEFJQUVnQXpZQ0ZDQURJQUUyQWhnTElBSWdCVThOQUNBRktBSUVJZ0ZCQVhGRkRRQUNRQUpBQWtBQ1FDQUJRUUp4UlFSQVFhQWZLQUlBSUFWR0JFQkJvQjhnQWpZQ0FFR1VIMEdVSHlnQ0FDQUFhaUlBTmdJQUlBSWdBRUVCY2pZQ0JDQUNRWndmS0FJQVJ3MEdRWkFmUVFBMkFnQkJuQjlCQURZQ0FBOExRWndmS0FJQUlBVkdCRUJCbkI4Z0FqWUNBRUdRSDBHUUh5Z0NBQ0FBYWlJQU5nSUFJQUlnQUVFQmNqWUNCQ0FBSUFKcUlBQTJBZ0FQQ3lBQlFYaHhJQUJxSVFBZ0FVSC9BVTBFUUNBQlFRTjJJUVFnQlNnQ0RDSUJJQVVvQWdnaUEwWUVRRUdJSDBHSUh5Z0NBRUYrSUFSM2NUWUNBQXdGQ3lBRElBRTJBZ3dnQVNBRE5nSUlEQVFMSUFVb0FoZ2hCaUFGSUFVb0Fnd2lBVWNFUUVHWUh5Z0NBQm9nQlNnQ0NDSURJQUUyQWd3Z0FTQUROZ0lJREFNTElBVkJGR29pQkNnQ0FDSURSUVJBSUFVb0FoQWlBMFVOQWlBRlFSQnFJUVFMQTBBZ0JDRUhJQU1pQVVFVWFpSUVLQUlBSWdNTkFDQUJRUkJxSVFRZ0FTZ0NFQ0lERFFBTElBZEJBRFlDQUF3Q0N5QUZJQUZCZm5FMkFnUWdBaUFBUVFGeU5nSUVJQUFnQW1vZ0FEWUNBQXdEQzBFQUlRRUxJQVpGRFFBQ1FDQUZLQUljSWdOQkFuUkJ1Q0ZxSWdRb0FnQWdCVVlFUUNBRUlBRTJBZ0FnQVEwQlFZd2ZRWXdmS0FJQVFYNGdBM2R4TmdJQURBSUxJQVpCRUVFVUlBWW9BaEFnQlVZYmFpQUJOZ0lBSUFGRkRRRUxJQUVnQmpZQ0dDQUZLQUlRSWdNRVFDQUJJQU0yQWhBZ0F5QUJOZ0lZQ3lBRktBSVVJZ05GRFFBZ0FTQUROZ0lVSUFNZ0FUWUNHQXNnQWlBQVFRRnlOZ0lFSUFBZ0Ftb2dBRFlDQUNBQ1Fad2ZLQUlBUncwQVFaQWZJQUEyQWdBUEN5QUFRZjhCVFFSQUlBQkJlSEZCc0I5cUlRRUNmMEdJSHlnQ0FDSURRUUVnQUVFRGRuUWlBSEZGQkVCQmlCOGdBQ0FEY2pZQ0FDQUJEQUVMSUFFb0FnZ0xJUUFnQVNBQ05nSUlJQUFnQWpZQ0RDQUNJQUUyQWd3Z0FpQUFOZ0lJRHd0Qkh5RURJQUJCLy8vL0IwMEVRQ0FBUVNZZ0FFRUlkbWNpQVd0MlFRRnhJQUZCQVhSclFUNXFJUU1MSUFJZ0F6WUNIQ0FDUWdBM0FoQWdBMEVDZEVHNElXb2hBUUpBQWtBQ1FFR01IeWdDQUNJRVFRRWdBM1FpQjNGRkJFQkJqQjhnQkNBSGNqWUNBQ0FCSUFJMkFnQWdBaUFCTmdJWURBRUxJQUJCR1NBRFFRRjJhMEVBSUFOQkgwY2JkQ0VESUFFb0FnQWhBUU5BSUFFaUJDZ0NCRUY0Y1NBQVJnMENJQU5CSFhZaEFTQURRUUYwSVFNZ0JDQUJRUVJ4YWlJSFFSQnFLQUlBSWdFTkFBc2dCeUFDTmdJUUlBSWdCRFlDR0FzZ0FpQUNOZ0lNSUFJZ0FqWUNDQXdCQ3lBRUtBSUlJZ0FnQWpZQ0RDQUVJQUkyQWdnZ0FrRUFOZ0lZSUFJZ0JEWUNEQ0FDSUFBMkFnZ0xRYWdmUWFnZktBSUFRUUZySWdCQmZ5QUFHellDQUFzTEJBQWpBQXNHQUNBQUpBQUxFQUFqQUNBQWEwRndjU0lBSkFBZ0FBdEtBUUYvSUFBZ0FVa0VRQ0FBSUFFZ0FoQUNEd3NnQWdSQUlBQWdBbW9oQXlBQklBSnFJUUVEUUNBRFFRRnJJZ01nQVVFQmF5SUJMUUFBT2dBQUlBSkJBV3NpQWcwQUN3c2dBQXY5RGdJUmZ3RitJd0JCTUdzaUJ5UUFRYmgvSVFnQ1FDQUZSUTBBSUFRc0FBQWlDVUgvQVhFaEN3SkFJQWxCQUVnRVFDQUxRZjRBYTBFQmRpSUdJQVZQRFFKQmJDRUlJQXRCL3dCcklndEIvd0ZMRFFJZ0JFRUJhaUVJUVFBaEJRTkFJQVVnQzA4RVFDQUxJUWdnQmlFTERBTUZJQUFnQldvZ0NDQUZRUUYyYWlJRUxRQUFRUVIyT2dBQUlBQWdCVUVCY21vZ0JDMEFBRUVQY1RvQUFDQUZRUUpxSVFVTUFRc0FDd0FMSUFVZ0MwME5BU0FIUWY4Qk5nSUVJQVlnQjBFRWFpQUhRUWhxSUFSQkFXb2lEaUFMRUF3aUJFR0lmMHNFUUNBRUlRZ01BZ3RCVkNFSUlBY29BZ2dpRUVFR1N3MEJJQWNvQWdRaUVVRUJkQ0lKUVFKcXJVSUJJQkN0aGlJWVFRRWdFSFFpRFVFQmFpSUZyVUlDaG54OFFndDhRdnovLy8vLy8vLy8vd0NEUXVRQ1ZnMEJRVkloQ0NBUlFmOEJTdzBCSUExQmYzTkJBblJCNUFKcXJTQVJRUUZxSWhWQkFYU3RJQmg4UWdoOFZBMEJJQXNnQkdzaEZpQUVJQTVxSVJjZ0JrR0FCR29pRWlBRlFRSjBhaUlSSUFscVFRSnFJUTRnQmtHRUJHb2hFMEdBZ0FJZ0VIUkJFSFloQ1VFQUlRVkJBU0VQSUExQkFXc2lGQ0VLQTBBZ0JTQVZSa1VFUUFKQUlBWWdCVUVCZENJSWFpOEJBQ0lFUWYvL0EwWUVRQ0FUSUFwQkFuUnFJQVU2QUFJZ0NrRUJheUVLUVFFaEJBd0JDeUFQUVFBZ0NTQUV3VW9iSVE4TElBZ2dFV29nQkRzQkFDQUZRUUZxSVFVTUFRc0xJQVlnRHpzQmdnUWdCaUFRT3dHQUJBSkFJQW9nRkVZRVFDQU5RUU4ySVFoQ0FDRVlRUUFoRHdOQUlBd2dGVVlFUUNBSUlBMUJBWFpxUVFOcUlnbEJBWFFoQ0VFQUlRUkJBQ0VLQTBCQkFDRUZJQW9nRFU4TkJBTkFJQVZCQWtaRkJFQWdFeUFGSUFsc0lBUnFJQlJ4UVFKMGFpQU9JQVVnQ21wcUxRQUFPZ0FDSUFWQkFXb2hCUXdCQ3dzZ0NrRUNhaUVLSUFRZ0NHb2dGSEVoQkF3QUN3QUZJQVlnREVFQmRHb3VBUUFoQ1NBT0lBOXFJZ1FnR0RjQUFFRUlJUVVEUUNBRklBbE9SUVJBSUFRZ0JXb2dHRGNBQUNBRlFRaHFJUVVNQVFzTElCaENnWUtFaUpDZ3dJQUJmQ0VZSUF4QkFXb2hEQ0FKSUE5cUlROE1BUXNBQ3dBTElBMUJBM1lnRFVFQmRtcEJBMm9oQ0VFQUlRVURRQ0FNSUJWR1JRUkFRUUFoQ1NBR0lBeEJBWFJxTGdFQUlnUkJBQ0FFUVFCS0d5RUVBMEFnQkNBSlJrVUVRQ0FUSUFWQkFuUnFJQXc2QUFJRFFDQUZJQWhxSUJSeElnVWdDa3NOQUFzZ0NVRUJhaUVKREFFTEN5QU1RUUZxSVF3TUFRc0xRWDhoQ0NBRkRRSUxJQkJCQVdvaENFRUFJUVVEUUNBRklBMUdSUVJBSUJFZ0V5QUZRUUowYWlJT0xRQUNRUUYwYWlJRUlBUXZBUUFpQ1VFQmFqc0JBQ0FPSUFnZ0NXZEJZSE5xSWdRNkFBTWdEaUFKSUFSMElBMXJPd0VBSUFWQkFXb2hCUXdCQ3dzQ1FBSkFJQVl2QVlJRUJFQWdCMEVjYWlJRUlCY2dGaEFOSWdoQmlIOUxEUUlnQjBFVWFpQUVJQklRRGlBSFFReHFJQVFnRWhBT1FRQWhCUU5BSUFkQkhHb2lCQkFQSUFWQit3RkxjZzBDSUFBZ0JXb2lCaUFIUVJScUlBUVFFRG9BQUNBR0lBZEJER29nQkJBUU9nQUJJQVZCQW5JaEJDQUhRUnhxRUE4RVFDQUVJUVVNQXdVZ0FDQUVhaUFIUVJScUlBZEJIR29pQkJBUU9nQUFJQVlnQjBFTWFpQUVFQkE2QUFNZ0JVRUVhaUVGREFFTEFBc0FDeUFIUVJ4cUlnUWdGeUFXRUEwaUNFR0lmMHNOQVNBSFFSUnFJQVFnRWhBT0lBZEJER29nQkNBU0VBNUJBQ0VGQTBBZ0IwRWNhaUlFRUE4Z0JVSDdBVXR5UlFSQUlBQWdCV29pQmlBSFFSUnFJQVFRRVRvQUFDQUdJQWRCREdvZ0JCQVJPZ0FCSUFWQkFuSWhCQ0FIUVJ4cUVBOEVRQ0FFSVFVRklBQWdCR29nQjBFVWFpQUhRUnhxSWdRUUVUb0FBQ0FHSUFkQkRHb2dCQkFST2dBRElBVkJCR29oQlF3Q0N3c0xBbjhEUUVHNmZ5RUlJQVZCL1FGTERRTWdBQ0FGYWlJR0lBZEJGR29nQjBFY2FpSUpFQkU2QUFBZ0JrRUJhaUVFSUFrUUQwRURSZ1JBSUFkQkRHb2hDRUVDREFJTElBVkIvQUZMRFFNZ0JpQUhRUXhxSUFkQkhHb2lCQkFST2dBQklBVkJBbW9oQlNBRUVBOUJBMGNOQUFzZ0FDQUZhaUVFSUFkQkZHb2hDRUVEQ3lBRUlBZ2dCMEVjYWhBUk9nQUFJQVpxSUFCcklRZ01BUXNDZndOQVFicC9JUWdnQlVIOUFVc05BaUFBSUFWcUlnWWdCMEVVYWlBSFFSeHFJZ2tRRURvQUFDQUdRUUZxSVFRZ0NSQVBRUU5HQkVBZ0IwRU1haUVJUVFJTUFnc2dCVUg4QVVzTkFpQUdJQWRCREdvZ0IwRWNhaUlFRUJBNkFBRWdCVUVDYWlFRklBUVFEMEVEUncwQUN5QUFJQVZxSVFRZ0IwRVVhaUVJUVFNTElBUWdDQ0FIUVJ4cUVCQTZBQUFnQm1vZ0FHc2hDQXNnQ0VHSWYwc05BUXNnQ0NFRVFRQWhCU0FCUVFCQk5CQURJUWxCQUNFS0EwQWdCQ0FGUndSQUlBQWdCV29pQmkwQUFDSUJRUXRMQkVCQmJDRUlEQU1GSUFrZ0FVRUNkR29pQVNBQktBSUFRUUZxTmdJQUlBVkJBV29oQlVFQklBWXRBQUIwUVFGMUlBcHFJUW9NQWdzQUN3dEJiQ0VJSUFwRkRRQWdDbWNpQlVFZmN5SUJRUXRMRFFBZ0EwRWdJQVZyTmdJQVFRRkJBaUFCZENBS2F5SURaMEVmY3lJQmRDQURSdzBBSUFBZ0JHb2dBVUVCYWlJQU9nQUFJQWtnQUVFQ2RHb2lBQ0FBS0FJQVFRRnFOZ0lBSUFrb0FnUWlBRUVDU1NBQVFRRnhjZzBBSUFJZ0JFRUJhallDQUNBTFFRRnFJUWdMSUFkQk1Hb2tBQ0FJQzZBRkFReC9Jd0JCRUdzaURDUUFBbjhnQkVFSFRRUkFJQXhDQURjRENDQU1RUWhxSWdVZ0F5QUVFQUlhUVd3Z0FDQUJJQUlnQlVFSUVBd2lBQ0FBSUFSTEd5QUFJQUJCaVg5Skd3d0JDeUFBUVFBZ0FTZ0NBRUVCYWlJTlFRRjBFQU1oRDBGVUlBTW9BQUFpQmtFUGNTSUFRUXBMRFFBYUlBSWdBRUVGYWpZQ0FDQURJQVJxSWdKQkJHc2hCeUFDUVFkcklRc2dBRUVHYWlFT1FRUWhBaUFHUVFSMklRVkJJQ0FBZENJSVFRRnlJUWxCQUNFQVFRRWhCaUFESVFRRFFBSkFJQVpCQVhGRkJFQURRQ0FGUVg5elFZQ0FnSUI0Y21naUJrRVlTVVVFUUNBQVFTUnFJUUFnQkNBTFRRUi9JQVJCQTJvRklBUWdDMnRCQTNRZ0FtcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMSUFJZ0JrRWVjU0lLYWtFQ2FpRUNJQVpCQVhaQkEyd2dBR29nQlNBS2RrRURjV29pQUNBTlR3MEJBbjhnQkNBTFN5QUNRUU4ySUFScUlnVWdCMHR4UlFSQUlBSkJCM0VoQWlBRkRBRUxJQVFnQjJ0QkEzUWdBbXBCSDNFaEFpQUhDeUlFS0FBQUlBSjJJUVVMSUFVZ0NFRUJhM0VpQmlBSVFRRjBRUUZySWdvZ0NXc2lFRWtFZnlBT1FRRnJCU0FGSUFweElnVWdFRUVBSUFVZ0NFNGJheUVHSUE0TElRVWdEeUFBUVFGMGFpQUdRUUZySWdvN0FRQWdBRUVCYWlFQUlBSWdCV29oQWlBSVFRRWdCbXNnQ2lBR1FRQktHeUFKYWlJSlNnUkFJQWxCQWtnTkFVRWdJQWxuSWdWcklRNUJBU0FGUVI5emRDRUlDeUFBSUExUERRQWdDa0VBUnlFR0FuOGdCQ0FMU3lBQ1FRTjFJQVJxSWdVZ0IwdHhSUVJBSUFKQkIzRWhBaUFGREFFTElBSWdCQ0FIYTBFRGRHcEJIM0VoQWlBSEN5SUVLQUFBSUFKMklRVU1BUXNMUVd3Z0NVRUJSdzBBR2tGUUlBQWdEVXNOQUJwQmJDQUNRU0JLRFFBYUlBRWdBRUVCYXpZQ0FDQUVJQUpCQjJwQkEzVnFJQU5yQ3lBTVFSQnFKQUFMOGdFQkFYOGdBa1VFUUNBQVFnQTNBZ0FnQUVFQU5nSVFJQUJDQURjQ0NFRzRmdzhMSUFBZ0FUWUNEQ0FBSUFGQkJHbzJBaEFnQWtFRVR3UkFJQUFnQVNBQ2FpSUJRUVJySWdNMkFnZ2dBQ0FES0FBQU5nSUFJQUZCQVdzdEFBQWlBUVJBSUFBZ0FXZEJGMnMyQWdRZ0FnOExJQUJCQURZQ0JFRi9Ed3NnQUNBQk5nSUlJQUFnQVMwQUFDSUROZ0lBQWtBQ1FBSkFJQUpCQW1zT0FnRUFBZ3NnQUNBQkxRQUNRUkIwSUFOeUlnTTJBZ0FMSUFBZ0FTMEFBVUVJZENBRGFqWUNBQXNnQVNBQ2FrRUJheTBBQUNJQlJRUkFJQUJCQURZQ0JFRnNEd3NnQUNBQlp5QUNRUU4wYTBFSmFqWUNCQ0FDQzBRQkFuOGdBU0FDTHdFQUlnTWdBU2dDQkdvaUJEWUNCQ0FBSUFOQkFuUkJvQjFxS0FJQUlBRW9BZ0JCQUNBRWEzWnhOZ0lBSUFFUUR4b2dBQ0FDUVFScU5nSUVDNThCQVFSL1FRTWhBU0FBS0FJRUlnSkJJRTBFUUNBQUtBSUlJZ0VnQUNnQ0VFOEVRQ0FBSUFKQkIzRTJBZ1FnQUNBQklBSkJBM1pySWdJMkFnZ2dBQ0FDS0FBQU5nSUFRUUFQQ3lBQUtBSU1JZ01nQVVZRVFFRUJRUUlnQWtFZ1NSc1BDeUFBSUFFZ0FTQURheUFDUVFOMklnUWdBU0FFYXlBRFNTSUJHeUlEYXlJRU5nSUlJQUFnQWlBRFFRTjBhellDQkNBQUlBUW9BQUEyQWdBTElBRUxTQUVFZnlBQUtBSUVJQUFvQWdCQkFuUnFJZ0l0QUFJZ0FpOEJBQ0VFSUFFZ0FTZ0NCQ0lGSUFJdEFBTWlBbW8yQWdRZ0FDQUVJQUVvQWdBZ0JYUkJBQ0FDYTNacU5nSUFDMUlCQkg4Z0FDZ0NCQ0FBS0FJQVFRSjBhaUlDTFFBQ0lBSXZBUUFoQkNBQklBSXRBQU1pQWlBQktBSUVhaUlGTmdJRUlBQWdCQ0FDUVFKMFFhQWRhaWdDQUNBQktBSUFRUUFnQld0MmNXbzJBZ0FMQ0FBZ0FFR0lmMHNMR2dBZ0FBUkFJQUVFUUNBQ0lBQWdBUkVDQUE4TElBQVFCZ3NMcGdnQ0RYOEJmaU1BUVJCcklna2tBQ0FKUVFBMkFnd2dDVUVBTmdJSUFuOENRQ0FEUWVnSmFpQURJQWxCQ0dvZ0NVRU1haUFCSUFJZ0EwR0FBV29RQ3lJUFFZaC9TdzBBUVZRZ0NTZ0NEQ0lFSUFBb0FnQWlBVUgvQVhGQkFXcExEUUVhSUFCQkJHb2hDeUFBSUFGQi80R0FlSEVnQkVFUWRFR0FnUHdIY1hJMkFnQkJmeUFFSUFSQkFFZ2JRUUZxSVFCQkFDRUJJQWtvQWdnaEJVRUFJUUlEUUNBQUlBSkdCRUFnQlVFRGF5RUJRUUFoQUFOQUFrQkJBQ0VDSUFBZ0FVNEVRQU5BSUFBZ0JVNE5BaUFESUFBZ0EycEI2QWxxTFFBQVFRSjBha0ZBYXlJQklBRW9BZ0FpQVVFQmFqWUNBQ0FCSUFOcUlBQTZBT2dISUFCQkFXb2hBQXdBQ3dBRkEwQWdBa0VFUmtVRVFDQURJQU1nQUNBQ2FpSUhha0hvQ1dvdEFBQkJBblJxUVVCcklnZ2dDQ2dDQUNJSVFRRnFOZ0lBSUFNZ0NHb2dCem9BNkFjZ0FrRUJhaUVDREFFTEN5QUFRUVJxSVFBTUFnc0FDd3NnQkVFQmFpRU9JQU1vQWdBaEIwRUFJUUJCQVNFSUEwQWdDQ0FPUmcwRElBNGdDR3NoQkNBRElBaEJBblJxS0FJQUlRVUNRQUpBQWtBQ1FBSkFBa0JCQVNBSWRFRUJkU0lOUVFGckRnZ0FBUVFDQkFRRUF3UUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUFJUUVEUUNBQ0lBWkdEUVVnQXlBQ0lBZHFhaTBBNkFjaENpQUxJQUZCQVhScUlnd2dCRG9BQVNBTUlBbzZBQUFnQWtFQmFpRUNJQUZCQVdvaEFRd0FDd0FMUVFBaEFpQUZRUUFnQlVFQVNoc2hDaUFBSVFFRFFDQUNJQXBHRFFRZ0N5QUJRUUYwYWlJR0lBTWdBaUFIYW1vdEFPZ0hJZ3c2QUFJZ0JpQUVPZ0FCSUFZZ0REb0FBQ0FHSUFRNkFBTWdBa0VCYWlFQ0lBRkJBbW9oQVF3QUN3QUxRUUFoQWlBRlFRQWdCVUVBU2hzaEJpQUVRUWgwUVlEK0EzRWhCQ0FBSVFFRFFDQUNJQVpHRFFNZ0N5QUJRUUYwYWlBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrTndBQUlBSkJBV29oQWlBQlFRUnFJUUVNQUFzQUMwRUFJUUlnQlVFQUlBVkJBRW9iSVFZZ0JFRUlkRUdBL2dOeElRUWdBQ0VCQTBBZ0FpQUdSZzBDSUFzZ0FVRUJkR29pQ2lBRUlBTWdBaUFIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSWhFM0FBZ2dDaUFSTndBQUlBSkJBV29oQWlBQlFRaHFJUUVNQUFzQUMwRUFJUUVnQlVFQUlBVkJBRW9iSVFvZ0JFRUlkRUdBL2dOeElRd2dBQ0VFQTBBZ0FTQUtSZzBCSUFzZ0JFRUJkR29oRUNBTUlBTWdBU0FIYW1vdEFPZ0hjcTFDZ1lDRWdKQ0F3QUIrSVJGQkFDRUNBMEFnQWlBTlRrVUVRQ0FRSUFKQkFYUnFJZ1lnRVRjQUdDQUdJQkUzQUJBZ0JpQVJOd0FJSUFZZ0VUY0FBQ0FDUVJCcUlRSU1BUXNMSUFGQkFXb2hBU0FFSUExcUlRUU1BQXNBQ3lBSVFRRnFJUWdnQlNBSGFpRUhJQVVnRFd3Z0FHb2hBQXdBQ3dBRklBTWdBa0VDZEdvaUIwRkFheUFCTmdJQUlBSkJBV29oQWlBSEtBSUFJQUZxSVFFTUFRc0FDd0FMSUE4TElBbEJFR29rQUF2eUFnRUdmeU1BUVNCcklnVWtBQ0FFS0FJQUlRWWdCVUVNYWlBQ0lBTVFEU0lEUVloL1RRUkFJQVJCQkdvaEFpQUFJQUZxSWdsQkEyc2hCRUVBSUFaQkVIWnJRUjl4SVFNRFFDQUZRUXhxRUE4Z0FDQUVUM0pGQkVBZ0FpQUZLQUlNSWdZZ0JTZ0NFQ0lIZENBRGRrRUJkR29pQ0MwQUFTRUtJQUFnQ0MwQUFEb0FBQ0FDSUFZZ0J5QUthaUlHZENBRGRrRUJkR29pQnkwQUFDRUlJQVVnQmlBSExRQUJhallDRUNBQUlBZzZBQUVnQUVFQ2FpRUFEQUVMQ3dOQUlBVkJER29RRHlFSElBVW9BZ3doQmlBRktBSVFJUVFnQUNBSlR5QUhja1VFUUNBQ0lBWWdCSFFnQTNaQkFYUnFJZ1l0QUFBaEJ5QUZJQVFnQmkwQUFXbzJBaEFnQUNBSE9nQUFJQUJCQVdvaEFBd0JDd3NEUUNBQUlBbFBSUVJBSUFJZ0JpQUVkQ0FEZGtFQmRHb2lCeTBBQVNFSUlBQWdCeTBBQURvQUFDQUFRUUZxSVFBZ0JDQUlhaUVFREFFTEMwRnNRV3dnQVNBRktBSVVJQVVvQWhoSEd5QUVRU0JIR3lFREN5QUZRU0JxSkFBZ0F3dlBGQUVqZnlNQVFkQUFheUlGSkFCQmJDRUpBa0FnQTBFS1NRMEFBa0FnQXlBQ0x3QUVJZ2NnQWk4QUFDSUlJQUl2QUFJaURXcHFRUVpxSWd4SkRRQWdCQzhCQWlFR0lBVkJQR29nQWtFR2FpSUNJQWdRRFNJSlFZaC9TdzBCSUFWQktHb2dBaUFJYWlJQ0lBMFFEU0lKUVloL1N3MEJJQVZCRkdvZ0FpQU5haUlDSUFjUURTSUpRWWgvU3cwQklBVWdBaUFIYWlBRElBeHJFQTBpQ1VHSWYwc05BU0FFUVFScUlRb2dBQ0FCYWlJZlFRTnJJU0JCQUNBR2EwRWZjU0VMSUFVb0FnZ2hFU0FGS0FJY0lSSWdCU2dDTUNFVElBVW9Ba1FoRkNBRktBSUVJUWtnQlNnQ0dDRU5JQVVvQWl3aERDQUZLQUpBSVFZZ0JTZ0NFQ0VoSUFVb0FpUWhJaUFGS0FJNElTTWdCU2dDVENFa0lBVW9BZ0FoRlNBRktBSVVJUllnQlNnQ0tDRVhJQVVvQWp3aEdFRUJJUThnQUNBQlFRTnFRUUoySWdScUlnTWdCR29pQWlBRWFpSVpJUVFnQWlFSUlBTWhCd05BSUE5QkFYRkZJQVFnSUU5eVJRUkFJQUFnQ2lBWUlBWjBJQXQyUVFKMGFpSU9Md0VBT3dBQUlBNHRBQUloR2lBT0xRQURJUkFnQnlBS0lCY2dESFFnQzNaQkFuUnFJZzR2QVFBN0FBQWdEaTBBQWlFYklBNHRBQU1oRHlBSUlBb2dGaUFOZENBTGRrRUNkR29pRGk4QkFEc0FBQ0FPTFFBQ0lSd2dEaTBBQXlFZElBUWdDaUFWSUFsMElBdDJRUUowYWlJT0x3RUFPd0FBSUE0dEFBSWhIaUFPTFFBRElRNGdBQ0FRYWlJbElBb2dHQ0FHSUJwcUlnWjBJQXQyUVFKMGFpSVFMd0VBT3dBQUlCQXRBQUlnRUMwQUF5RW1JQWNnRDJvaUp5QUtJQmNnRENBYmFpSWFkQ0FMZGtFQ2RHb2lCeThCQURzQUFDQUhMUUFDSVF3Z0J5MEFBeUVRSUFnZ0hXb2lHeUFLSUJZZ0RTQWNhaUlQZENBTGRrRUNkR29pQ0M4QkFEc0FBQ0FJTFFBQ0lRMGdDQzBBQXlFY0lBUWdEbW9pSFNBS0lCVWdDU0FlYWlJT2RDQUxka0VDZEdvaUNTOEJBRHNBQUNBR2FpRUFRUU1oQndKL0lCUWdKRWtFUUNBQUlRWkJBd3dCQ3lBQVFRZHhJUVlnRkNBQVFRTjJheUlVS0FBQUlSaEJBQXNnQ1MwQUF5RWVJQWt0QUFJaENDQU1JQnBxSVFBZ0V5QWpTUVIvSUFBRklCTWdBRUVEZG1zaUV5Z0FBQ0VYUVFBaEJ5QUFRUWR4Q3lFTUlBMGdEMm9oQUNBSGNpRUpRUU1oRHdKL0lCSWdJa2tFUUNBQUlRMUJBd3dCQ3lBQVFRZHhJUTBnRWlBQVFRTjJheUlTS0FBQUlSWkJBQXNnQ0NBT2FpRUFJQWx5SUJFZ0lVa0VmeUFBQlNBUklBQkJBM1pySWhFb0FBQWhGVUVBSVE4Z0FFRUhjUXNoQ1NBbElDWnFJUUFnRUNBbmFpRUhJQnNnSEdvaENDQWRJQjVxSVFRZ0QzSkZJUThNQVFzTElBVWdERFlDTENBRklBWTJBa0FnQlNBTk5nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUlnQjBrZ0FDQURTM0lOQUVGc0lRa2dDQ0FaU3cwQklBTkJBMnNoQ1FOQUlBVkJQR29RRDBVZ0FDQUpTWEVFUUNBQUlBb2dCU2dDUENJTklBVW9Ba0FpREhRZ0MzWkJBblJxSWc0dkFRQTdBQUFnQUNBT0xRQURhaUlHSUFvZ0RTQU1JQTR0QUFKcUlnQjBJQXQyUVFKMGFpSU1Md0VBT3dBQUlBVWdBQ0FNTFFBQ2FqWUNRQ0FHSUF3dEFBTnFJUUFNQVFVZ0EwRUNheUVNQTBBZ0JVRThhaEFQSVFZZ0JTZ0NQQ0VOSUFVb0FrQWhDU0FBSUF4TElBWnlSUVJBSUFBZ0NpQU5JQWwwSUF0MlFRSjBhaUlHTHdFQU93QUFJQVVnQ1NBR0xRQUNhallDUUNBQUlBWXRBQU5xSVFBTUFRc0xBMEFnQUNBTVMwVUVRQ0FBSUFvZ0RTQUpkQ0FMZGtFQ2RHb2lCaThCQURzQUFDQUFJQVl0QUFOcUlRQWdDU0FHTFFBQ2FpRUpEQUVMQ3dKQUlBQWdBMDhOQUNBQUlBb2dEU0FKZENBTGRpSUFRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSklBTXRBQUpxSVFrTUFRc2dDVUVmU3cwQVFTQWdDU0FLSUFCQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFrTElBSkJBMnNoREFOQUlBVkJLR29RRDBVZ0J5QU1TWEVFUUNBSElBb2dCU2dDS0NJR0lBVW9BaXdpQUhRZ0MzWkJBblJxSWcwdkFRQTdBQUFnQnlBTkxRQURhaUlESUFvZ0JpQUFJQTB0QUFKcUlnQjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBQ0FHTFFBQ2FqWUNMQ0FESUFZdEFBTnFJUWNNQVFVZ0FrRUNheUVHQTBBZ0JVRW9haEFQSVFNZ0JTZ0NLQ0VNSUFVb0Fpd2hBQ0FHSUFkSklBTnlSUVJBSUFjZ0NpQU1JQUIwSUF0MlFRSjBhaUlETHdFQU93QUFJQVVnQUNBRExRQUNhallDTENBSElBTXRBQU5xSVFjTUFRc0xBMEFnQmlBSFNVVUVRQ0FISUFvZ0RDQUFkQ0FMZGtFQ2RHb2lBeThCQURzQUFDQUhJQU10QUFOcUlRY2dBQ0FETFFBQ2FpRUFEQUVMQ3dKQUlBSWdCMDBOQUNBSElBb2dEQ0FBZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBQUlBTXRBQUpxSVFBTUFRc2dBRUVmU3cwQVFTQWdBQ0FLSUFKQkFuUnFMUUFDYWlJQUlBQkJJRThiSVFBTElCbEJBMnNoREFOQUlBVkJGR29RRDBVZ0NDQU1TWEVFUUNBSUlBb2dCU2dDRkNJR0lBVW9BaGdpQW5RZ0MzWkJBblJxSWcwdkFRQTdBQUFnQ0NBTkxRQURhaUlESUFvZ0JpQUNJQTB0QUFKcUlnSjBJQXQyUVFKMGFpSUdMd0VBT3dBQUlBVWdBaUFHTFFBQ2FqWUNHQ0FESUFZdEFBTnFJUWdNQVFVZ0dVRUNheUVEQTBBZ0JVRVVhaEFQSVFJZ0JTZ0NGQ0VHSUFVb0FoZ2hCeUFESUFoSklBSnlSUVJBSUFnZ0NpQUdJQWQwSUF0MlFRSjBhaUlDTHdFQU93QUFJQVVnQnlBQ0xRQUNhallDR0NBSUlBSXRBQU5xSVFnTUFRc0xBMEFnQXlBSVNVVUVRQ0FJSUFvZ0JpQUhkQ0FMZGtFQ2RHb2lBaThCQURzQUFDQUlJQUl0QUFOcUlRZ2dCeUFDTFFBQ2FpRUhEQUVMQ3dKQUlBZ2dHVThOQUNBSUlBb2dCaUFIZENBTGRpSUNRUUowYWlJRExRQUFPZ0FBSUFNdEFBTkJBVVlFUUNBSElBTXRBQUpxSVFjTUFRc2dCMEVmU3cwQVFTQWdCeUFLSUFKQkFuUnFMUUFDYWlJQ0lBSkJJRThiSVFjTEEwQWdCUkFQUlNBRUlDQkpjUVJBSUFRZ0NpQUZLQUlBSWdZZ0JTZ0NCQ0lDZENBTGRrRUNkR29pREM4QkFEc0FBQ0FFSUF3dEFBTnFJZ01nQ2lBR0lBSWdEQzBBQW1vaUFuUWdDM1pCQW5ScUlnUXZBUUE3QUFBZ0JTQUNJQVF0QUFKcU5nSUVJQU1nQkMwQUEyb2hCQXdCQlNBZlFRSnJJUU1EUUNBRkVBOGhBaUFGS0FJQUlRWWdCU2dDQkNFSUlBTWdCRWtnQW5KRkJFQWdCQ0FLSUFZZ0NIUWdDM1pCQW5ScUlnSXZBUUE3QUFBZ0JTQUlJQUl0QUFKcU5nSUVJQVFnQWkwQUEyb2hCQXdCQ3dzRFFDQURJQVJKUlFSQUlBUWdDaUFHSUFoMElBdDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0FpMEFBMm9oQkNBSUlBSXRBQUpxSVFnTUFRc0xBa0FnQkNBZlR3MEFJQVFnQ2lBR0lBaDBJQXQySWdKQkFuUnFJZ010QUFBNkFBQWdBeTBBQTBFQlJnUkFJQWdnQXkwQUFtb2hDQXdCQ3lBSVFSOUxEUUJCSUNBSUlBb2dBa0VDZEdvdEFBSnFJZ0lnQWtFZ1R4c2hDQXRCYkVGc1FXeEJiRUZzUVd4QmJFRnNJQUVnQ0VFZ1J4c2dCU2dDQ0NBRktBSU1SeHNnQjBFZ1J4c2dCU2dDSENBRktBSWdSeHNnQUVFZ1J4c2dCU2dDTUNBRktBSTBSeHNnQ1VFZ1J4c2dCU2dDUkNBRktBSklSeHNoQ1F3SkN3QUxBQXNBQ3dBTEFBc0FDd0FMQUF0QmJDRUpDeUFGUWRBQWFpUUFJQWtMN0JBQkhuOGpBRUhRQUdzaUJTUUFRV3doQ1FKQUlBTkJDa2tOQUFKQUlBTWdBaThBQkNJR0lBSXZBQUFpQnlBQ0x3QUNJZ2hxYWtFR2FpSU9TUTBBSUFRdkFRSWhEeUFGUVR4cUlBSkJCbW9pQWlBSEVBMGlDVUdJZjBzTkFTQUZRU2hxSUFJZ0Iyb2lBaUFJRUEwaUNVR0lmMHNOQVNBRlFSUnFJQUlnQ0dvaUFpQUdFQTBpQ1VHSWYwc05BU0FGSUFJZ0Jtb2dBeUFPYXhBTklnbEJpSDlMRFFFZ0JFRUVhaUVLSUFBZ0FXb2lIRUVEYXlFZFFRQWdEMnRCSDNFaEN5QUZLQUlJSVJFZ0JTZ0NIQ0VTSUFVb0FqQWhFeUFGS0FKRUlSUWdCU2dDQkNFSklBVW9BaGdoQmlBRktBSXNJUWNnQlNnQ1FDRUlJQVVvQWhBaEhpQUZLQUlrSVI4Z0JTZ0NPQ0VnSUFVb0Frd2hJU0FGS0FJQUlSVWdCU2dDRkNFV0lBVW9BaWdoRnlBRktBSThJUmhCQVNFTklBQWdBVUVEYWtFQ2RpSUNhaUlPSUFKcUlnOGdBbW9pR1NFRUlBOGhBaUFPSVFNRFFDQU5SU0FFSUIxUGNrVUVRQ0FLSUJnZ0NIUWdDM1pCQVhScUlnd3RBQUVoRFNBQUlBd3RBQUE2QUFBZ0NpQVhJQWQwSUF0MlFRRjBhaUlNTFFBQklSQWdBeUFNTFFBQU9nQUFJQW9nRmlBR2RDQUxka0VCZEdvaURDMEFBU0VhSUFJZ0RDMEFBRG9BQUNBS0lCVWdDWFFnQzNaQkFYUnFJZ3d0QUFFaEd5QUVJQXd0QUFBNkFBQWdDaUFZSUFnZ0RXb2lDSFFnQzNaQkFYUnFJZ3d0QUFFaERTQUFJQXd0QUFBNkFBRWdDaUFYSUFjZ0VHb2lCM1FnQzNaQkFYUnFJZ3d0QUFFaEVDQURJQXd0QUFBNkFBRWdDaUFXSUFZZ0dtb2lESFFnQzNaQkFYUnFJZ1l0QUFFaEdpQUNJQVl0QUFBNkFBRWdDaUFWSUFrZ0cyb2lHM1FnQzNaQkFYUnFJZ2t0QUFFaElpQUVJQWt0QUFBNkFBRWdDQ0FOYWlFR1FRTWhDUUovSUJRZ0lVa0VRRUVESVEwZ0Jnd0JDeUFVSUFaQkEzWnJJaFFvQUFBaEdFRUFJUTBnQmtFSGNRc2hDQ0FISUJCcUlRWWdFeUFnU1FSL0lBWUZJQk1nQmtFRGRtc2lFeWdBQUNFWFFRQWhDU0FHUVFkeEN5RUhJQXdnR21vaERDQUpJQTF5SVJCQkF5RU5BbjhnRWlBZlNRUkFJQXdoQmtFRERBRUxJQXhCQjNFaEJpQVNJQXhCQTNackloSW9BQUFoRmtFQUN5QWJJQ0pxSVF3Z0VISWhFQ0FSSUI1SkJIOGdEQVVnRVNBTVFRTjJheUlSS0FBQUlSVkJBQ0VOSUF4QkIzRUxJUWtnQkVFQ2FpRUVJQUpCQW1vaEFpQURRUUpxSVFNZ0FFRUNhaUVBSUEwZ0VISkZJUTBNQVFzTElBVWdCellDTENBRklBZzJBa0FnQlNBR05nSVlJQVVnQ1RZQ0JDQUZJQlEyQWtRZ0JTQVROZ0l3SUFVZ0VqWUNIQ0FGSUJFMkFnZ2dCU0FZTmdJOElBVWdGellDS0NBRklCWTJBaFFnQlNBVk5nSUFJQUFnRGtzZ0F5QVBTM0lOQUVGc0lRa2dBaUFaU3cwQklBNUJBMnNoQ1FOQUlBVkJQR29RRHlBQUlBbFBja1VFUUNBS0lBVW9BandpQmlBRktBSkFJZ2QwSUF0MlFRRjBhaUlJTFFBQklRd2dBQ0FJTFFBQU9nQUFJQW9nQmlBSElBeHFJZ1owSUF0MlFRRjBhaUlITFFBQUlRZ2dCU0FHSUFjdEFBRnFOZ0pBSUFBZ0NEb0FBU0FBUVFKcUlRQU1BUXNMQTBBZ0JVRThhaEFQSVFjZ0JTZ0NQQ0VHSUFVb0FrQWhDU0FBSUE1UElBZHlSUVJBSUFvZ0JpQUpkQ0FMZGtFQmRHb2lCaTBBQUNFSElBVWdDU0FHTFFBQmFqWUNRQ0FBSUFjNkFBQWdBRUVCYWlFQURBRUxDd05BSUFBZ0RrOUZCRUFnQ2lBR0lBbDBJQXQyUVFGMGFpSUhMUUFCSUFBZ0J5MEFBRG9BQUNBQVFRRnFJUUFnQ1dvaENRd0JDd3NnRDBFRGF5RUFBMEFnQlVFb2FoQVBJQUFnQTAxeVJRUkFJQW9nQlNnQ0tDSUdJQVVvQWl3aUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBRElBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFpd2dBeUFJT2dBQklBTkJBbW9oQXd3QkN3c0RRQ0FGUVNocUVBOGhCeUFGS0FJb0lRWWdCU2dDTENFQUlBTWdEMDhnQjNKRkJFQWdDaUFHSUFCMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBQUlBWXRBQUZxTmdJc0lBTWdCem9BQUNBRFFRRnFJUU1NQVFzTEEwQWdBeUFQVDBVRVFDQUtJQVlnQUhRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FESUFjdEFBQTZBQUFnQTBFQmFpRURJQUFnQ0dvaEFBd0JDd3NnR1VFRGF5RURBMEFnQlVFVWFoQVBJQUlnQTA5eVJRUkFJQW9nQlNnQ0ZDSUdJQVVvQWhnaUIzUWdDM1pCQVhScUlnZ3RBQUVoRGlBQ0lBZ3RBQUE2QUFBZ0NpQUdJQWNnRG1vaUJuUWdDM1pCQVhScUlnY3RBQUFoQ0NBRklBWWdCeTBBQVdvMkFoZ2dBaUFJT2dBQklBSkJBbW9oQWd3QkN3c0RRQ0FGUVJScUVBOGhCeUFGS0FJVUlRWWdCU2dDR0NFRElBSWdHVThnQjNKRkJFQWdDaUFHSUFOMElBdDJRUUYwYWlJR0xRQUFJUWNnQlNBRElBWXRBQUZxTmdJWUlBSWdCem9BQUNBQ1FRRnFJUUlNQVFzTEEwQWdBaUFaVDBVRVFDQUtJQVlnQTNRZ0MzWkJBWFJxSWdjdEFBRWhDQ0FDSUFjdEFBQTZBQUFnQWtFQmFpRUNJQU1nQ0dvaEF3d0JDd3NEUUNBRkVBOGdCQ0FkVDNKRkJFQWdDaUFGS0FJQUlnSWdCU2dDQkNJR2RDQUxka0VCZEdvaUJ5MEFBU0VJSUFRZ0J5MEFBRG9BQUNBS0lBSWdCaUFJYWlJQ2RDQUxka0VCZEdvaUJpMEFBQ0VISUFVZ0FpQUdMUUFCYWpZQ0JDQUVJQWM2QUFFZ0JFRUNhaUVFREFFTEN3TkFJQVVRRHlFSElBVW9BZ0FoQmlBRktBSUVJUUlnQkNBY1R5QUhja1VFUUNBS0lBWWdBblFnQzNaQkFYUnFJZ1l0QUFBaEJ5QUZJQUlnQmkwQUFXbzJBZ1FnQkNBSE9nQUFJQVJCQVdvaEJBd0JDd3NEUUNBRUlCeFBSUVJBSUFvZ0JpQUNkQ0FMZGtFQmRHb2lCeTBBQVNFSUlBUWdCeTBBQURvQUFDQUVRUUZxSVFRZ0FpQUlhaUVDREFFTEMwRnNRV3hCYkVGc1FXeEJiRUZzUVd3Z0FTQUNRU0JIR3lBRktBSUlJQVVvQWd4SEd5QURRU0JIR3lBRktBSWNJQVVvQWlCSEd5QUFRU0JIR3lBRktBSXdJQVVvQWpSSEd5QUpRU0JIR3lBRktBSkVJQVVvQWtoSEd5RUpEQUVMUVd3aENRc2dCVUhRQUdva0FDQUpDMWdCQTM4Q1FDQUFLQUtRNndFaUFVVU5BQ0FCS0FJQUlBRkJ0TlVCYWlnQ0FDSUNJQUZCdU5VQmFpZ0NBQ0lERUJNZ0FnUkFJQU1nQVNBQ0VRSUFEQUVMSUFFUUJnc2dBRUVBTmdLZzZ3RWdBRUlBTndPUTZ3RUw2UU1DQkg4Q2ZpQUFRUUJCS0JBRElRUWdBa0VCUVFVZ0F4c2lBRWtFUUNBQUR3c2dBVVVFUUVGL0R3dEJBU0VHQWtBQ1FDQURRUUZHRFFBZ0F5RUdJQUVvQUFBaUJVR282cjVwUmcwQVFYWWhBeUFGUVhCeFFkRFV0TUlCUncwQlFRZ2hBeUFDUVFoSkRRRWdBVFVBQkNFSUlBUkJBVFlDRkNBRUlBZzNBd0JCQUE4TElBRWdBaUFHRUJvaUF5QUNTdzBBSUFRZ0F6WUNHRUZ5SVFNZ0FDQUJhaUlGUVFGckxRQUFJZ0pCQ0hFTkFDQUNRU0J4SWdaRkJFQkJjQ0VESUFVdEFBQWlCVUduQVVzTkFTQUZRUWR4clVJQklBVkJBM1pCQ21xdGhpSUlRZ09JZmlBSWZDRUpJQUJCQVdvaEFBc2dBa0VHZGlFRklBSkJBblpCQUNFREFrQUNRQUpBQWtBZ0FrRURjVUVCYXc0REFBRUNBd3NnQUNBQmFpMEFBQ0VESUFCQkFXb2hBQXdDQ3lBQUlBRnFMd0FBSVFNZ0FFRUNhaUVBREFFTElBQWdBV29vQUFBaEF5QUFRUVJxSVFBTFFRRnhJUUlDZmdKQUFrQUNRQUpBSUFWQkFXc09Bd0VDQXdBTFFuOGdCa1VOQXhvZ0FDQUJhakVBQUF3REN5QUFJQUZxTXdBQVFvQUNmQXdDQ3lBQUlBRnFOUUFBREFFTElBQWdBV29wQUFBTElRZ2dCQ0FDTmdJZ0lBUWdBellDSENBRUlBZzNBd0JCQUNFRElBUkJBRFlDRkNBRUlBZ2dDU0FHR3lJSU53TUlJQVJDZ0lBSUlBZ2dDRUtBZ0FoYUd6NENFQXNnQXd0ZkFRRi9RYmgvSVFNZ0FVRUJRUVVnQWhzaUFrOEVmeUFBSUFKcVFRRnJMUUFBSWdCQkEzRkJBblJCb0I1cUtBSUFJQUpxSUFCQkJIWkJESEZCc0I1cUtBSUFhaUFBUVNCeElnRkZhaUFCUVFWMklBQkJ3QUJKY1dvRlFiaC9Dd3NNQUNBQUlBRWdBa0VBRUJrTGx3TUNCWDhDZmlNQVFVQnFJZ1FrQUFKQUEwQWdBVUVGVHdSQUFrQWdBQ2dBQUVGd2NVSFExTFRDQVVZRVFFSitJUWNnQVVFSVNRMEVJQUFvQUFRaUFrRjNTdzBFSUFKQkNHb2lBeUFCU3cwRUlBSkJnWDlKRFFFTUJBc2dCRUVZYWlBQUlBRVFHeUVDUW40Z0JDa0RHRUlBSUFRb0FpeEJBVWNiSUFJYklnZENmVllOQXlBSElBaDhJZ2dnQjFSQ2ZpRUhEUU1DUUFKQUlBRkJDRWtOQUNBQUtBQUFRWEJ4UWREVXRNSUJSdzBBSUFBb0FBUWlBa0YzU3cwRlFiaC9JQUpCQ0dvaUFpQUJJQUpKR3lFRERBRUxJQVJCR0dvZ0FDQUJFQnNpQWtHSWYwc0VRQ0FDSVFNTUFRdEJ1SDhoQXlBQ0RRQWdBU0FFS0FJd0lnSnJJUVVnQUNBQ2FpRUdBMEFnQmlBRklBUkJER29RSFNJRFFZaC9TdzBCSUFOQkEyb2lBaUFGU3dSQVFiaC9JUU1NQWdzZ0JTQUNheUVGSUFJZ0Jtb2hCaUFFS0FJUVJRMEFDeUFFS0FJNEJIOUJ1SDhoQXlBRlFRUkpEUUVnQmtFRWFnVWdCZ3NnQUdzaEF3c2dBMEdJZjBzTkF3c2dBU0FEYXlFQklBQWdBMm9oQUF3QkN3dENmaUFJSUFFYklRY0xJQVJCUUdza0FDQUhDMlFCQVg5QnVIOGhBd0pBSUFGQkEwa05BQ0FBTFFBQ0lRRWdBaUFBTHdBQUlnQkJBWEUyQWdRZ0FpQUFRUUYyUVFOeElnTTJBZ0FnQWlBQUlBRkJFSFJ5UVFOMklnQTJBZ2dDUUFKQUlBTkJBV3NPQXdJQkFBRUxRV3dQQ3lBQUlRTUxJQU1MUkFFQ2Z5QUJJQUlvQWdRaUF5QUJLQUlFYWlJRU5nSUVJQUFnQTBFQ2RFR2dIV29vQWdBZ0FTZ0NBRUVBSUFScmRuRTJBZ0FnQVJBUEdpQUFJQUpCQ0dvMkFnUUx6Z0VCQm45QnVuOGhDZ0pBSUFJb0FnUWlDQ0FDS0FJQUlnbHFJZzBnQVNBQWEwc05BRUZzSVFvZ0NTQUVJQU1vQWdBaUMydExEUUFnQUNBSmFpSUVJQUlvQWdnaURHc2hBaUFBSUFGQklHc2lBQ0FMSUFsQkFCQWdJQU1nQ1NBTGFqWUNBQUpBQWtBZ0JDQUZheUFNVHdSQUlBSWhCUXdCQ3lBTUlBUWdCbXRMRFFJZ0J5QUhJQUlnQldzaUFtb2lBU0FJYWs4RVFDQUVJQUVnQ0JBS0dnd0NDeUFDSUFocUlRZ2dCQ0FCUVFBZ0Ftc1FDaUFDYXlFRUN5QUVJQUFnQlNBSVFRRVFJQXNnRFNFS0N5QUtDOGNFQVFKL0lBQWdBMm9oQmdKQUlBTkJCMHdFUUFOQUlBQWdCazhOQWlBQUlBSXRBQUE2QUFBZ0FFRUJhaUVBSUFKQkFXb2hBZ3dBQ3dBTElBUkJBVVlFUUFKQUlBQWdBbXNpQlVFSFRRUkFJQUFnQWkwQUFEb0FBQ0FBSUFJdEFBRTZBQUVnQUNBQ0xRQUNPZ0FDSUFBZ0FpMEFBem9BQXlBQUlBSWdCVUVDZENJRlFjQWVhaWdDQUdvaUFpZ0FBRFlBQkNBQ0lBVkI0QjVxS0FJQWF5RUNEQUVMSUFBZ0Fpa0FBRGNBQUFzZ0FrRUlhaUVDSUFCQkNHb2hBQXNnQVNBR1R3UkFJQUFnQTJvaEFTQUVRUUZISUFBZ0FtdEJEMHB5UlFSQUEwQWdBQ0FDS1FBQU53QUFJQUpCQ0dvaEFpQUFRUWhxSWdBZ0FVa05BQXdEQ3dBTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dBMEVSU1EwQklBQkJFR29oQUFOQUlBQWdBaWtBRURjQUFDQUFJQUlwQUJnM0FBZ2dBQ0FDS1FBZ053QVFJQUFnQWlrQUtEY0FHQ0FDUVNCcUlRSWdBRUVnYWlJQUlBRkpEUUFMREFFTEFrQWdBQ0FCU3dSQUlBQWhBUXdCQ3lBQklBQnJJUVVDUUNBRVFRRkhJQUFnQW10QkQwcHlSUVJBSUFJaEF3TkFJQUFnQXlrQUFEY0FBQ0FEUVFocUlRTWdBRUVJYWlJQUlBRkpEUUFMREFFTElBQWdBaWtBQURjQUFDQUFJQUlwQUFnM0FBZ2dCVUVSU0EwQUlBQkJFR29oQUNBQ0lRTURRQ0FBSUFNcEFCQTNBQUFnQUNBREtRQVlOd0FJSUFBZ0F5a0FJRGNBRUNBQUlBTXBBQ2czQUJnZ0EwRWdhaUVESUFCQklHb2lBQ0FCU1EwQUN3c2dBaUFGYWlFQ0N3TkFJQUVnQms4TkFTQUJJQUl0QUFBNkFBQWdBVUVCYWlFQklBSkJBV29oQWd3QUN3QUxDNjRIQWdWL0FYNGpBRUdBQVdzaUVTUUFJQkVnQXpZQ2ZFRi9JUThDUUFKQUFrQUNRQUpBSUFJT0JBRUFBd0lFQ3lBR1JRUkFRYmgvSVE4TUJBdEJiQ0VQSUFVdEFBQWlBaUFEU3cwRElBZ2dBa0VDZENJQ2FpZ0NBQ0VESUFJZ0Iyb29BZ0FoQWlBQVFRQTZBQXNnQUVJQU53SUFJQUFnQWpZQ0RDQUFJQU02QUFvZ0FFRUFPd0VJSUFFZ0FEWUNBRUVCSVE4TUF3c2dBU0FKTmdJQVFRQWhEd3dDQ3lBS1JRUkFRV3doRHd3Q0MwRUFJUThnQzBVZ0RFRVpTSElOQVVFSUlBUjBRUWhxSVFCQkFDRURBMEFnQUNBRFRRMENJQU5CUUdzaEF3d0FDd0FMUVd3aER5QVJJQkZCL0FCcUlCRkIrQUJxSUFVZ0JoQU1JZ05CaUg5TERRQWdFU2dDZUNJQ0lBUkxEUUFnRVNnQ2ZFRUJhaUVKSUFCQkNHb2hDMEdBZ0FJZ0FuUkJFSFVoQlVFQklSQkJBU0FDZENJUFFRRnJJZ29oRWdOQUlBa2dEa2NFUUFKQUlCRWdEa0VCZENJRWFpOEJBQ0lNUWYvL0EwWUVRQ0FMSUJKQkEzUnFJQTQyQWdRZ0VrRUJheUVTUVFFaERBd0JDeUFRUVFBZ0JTQU13VW9iSVJBTElBUWdEV29nRERzQkFDQU9RUUZxSVE0TUFRc0xJQUFnQWpZQ0JDQUFJQkEyQWdBQ1FDQUtJQkpHQkVBZ0RVSHFBR29oQmtFQUlSQkJBQ0VNQTBBZ0NTQVFSZ1JBSUE5QkEzWWdEMEVCZG1wQkEyb2lCVUVCZENFRVFRQWhERUVBSVJJRFFFRUFJUTRnRHlBU1RRMEVBMEFnRGtFQ1J3UkFJQXNnQlNBT2JDQU1haUFLY1VFRGRHb2dCaUFPSUJKcWFpMEFBRFlDQkNBT1FRRnFJUTRNQVFzTElCSkJBbW9oRWlBRUlBeHFJQXB4SVF3TUFBc0FCU0FSSUJCQkFYUnFMZ0VBSVFVZ0JpQU1haUlFSUJNM0FBQkJDQ0VPQTBBZ0JTQU9TZ1JBSUFRZ0Rtb2dFemNBQUNBT1FRaHFJUTRNQVFzTElCTkNnWUtFaUpDZ3dJQUJmQ0VUSUJCQkFXb2hFQ0FGSUF4cUlRd01BUXNBQ3dBTElBOUJBM1lnRDBFQmRtcEJBMm9oQlVFQUlSQkJBQ0VPQTBBZ0NTQVFSZzBCUVFBaERDQVJJQkJCQVhScUxnRUFJZ1JCQUNBRVFRQktHeUVFQTBBZ0JDQU1Sd1JBSUFzZ0RrRURkR29nRURZQ0JBTkFJQVVnRG1vZ0NuRWlEaUFTU3cwQUN5QU1RUUZxSVF3TUFRc0xJQkJCQVdvaEVBd0FDd0FMSUFKQkFXb2hCVUVBSVF3RFFDQU1JQTlIQkVBZ0RTQUxJQXhCQTNScUlna29BZ1FpQkVFQmRHb2lBaUFDTHdFQUlnWkJBV283QVFBZ0NTQUZJQVpuUVdCemFpSUNPZ0FESUFrZ0JpQUNkQ0FQYXpzQkFDQUpJQWdnQkVFQ2RDSUNhaWdDQURvQUFpQUpJQUlnQjJvb0FnQTJBZ1FnREVFQmFpRU1EQUVMQ3lBQklBQTJBZ0FnQXlFUEN5QVJRWUFCYWlRQUlBOEw3Vm9DTzM4R2ZpTUFRZUFCYXlJRUpBQUNRRUd3N0FrUUJTSUZSUVJBUVVBaEJ3d0JDeUFGUWdBM0F2VHFBU0FGUVFBMkFzVHJBU0FGUVFBMkFyVHJBU0FGUWdBM0FwenJBU0FGUVFBMkFyanBBU0FGUVFBMkFxenNDU0FGUWdBM0F0VHJBU0FGUWdBM0FxenJBU0FGUWdBM0E0anJBU0FGUWdBM0F1VHFBU0FGUWdBM0F1VHJBU0FGUVlHQWdNQUFOZ0s4NndFZ0JVSUFOd0trNndFZ0JVSDg2Z0ZxUVFBMkFnQWdCVUdRNndGcVFnQTNBd0FnQlJBWUlBVkJyTlVCYWlFVUlBVkIrT3NCYWlFY0lBVkJzT29CYWlFaUlBVkJvREJxSVNvZ0JVR1lJR29oS3lBRlFhalFBR29oSGlBRlFSQnFJU3dnQlVFSWFpRW9JQVZCQkdvaExTQUZRY0RwQVdvaEtTQUZRWWpyQVdvZ0JFR1VBV29oTHlBRVFZd0JhaUV3SUFSQmhBRnFJVEVnQkVIY0FHb2hNaUFFUWRRQWFpRXpJQVJCekFCcUlUUWdBQ0VkQWtBQ1FBSkFBa0FDUUFOQVFRRkJCU0FGS0FMazZnRWJJUVlDUUFOQUlBTWdCa2tOQVNBQ0tBQUFRWEJ4UWREVXRNSUJSZ1JBUWJoL0lRY2dBMEVJU1EwSUlBSW9BQVFpRGtGM1N3UkFRWEloQnd3SkN5QURJQTVCQ0dvaUNVa05DQ0FPUVlCL1N3UkFJQWtoQnd3SkN5QURJQWxySVFNZ0FpQUphaUVDREFFTEN5QUZRZ0EzQXF6cEFTQUZRZ0EzQStqcEFTQUZRUUEyQXBqckFTQUZRZ0EzQTREcUFTQUZRZ00zQS9qcEFTQUZRYlRwQVdwQ0FEY0NBQ0FGUWZEcEFXcENBRGNEQUNBRlFhalFBR29pQ1VHTWdJRGdBRFlDQUNBRlFhelFBV3BCNEJJcEFnQTNBZ0FnQlVHMDBBRnFRZWdTS0FJQU5nSUFJQVVnQlVFUWFqWUNBQ0FGSUFWQm9EQnFOZ0lFSUFVZ0JVR1lJR28yQWdnZ0JTQUpOZ0lNSUFWQkFVRUZJQVVvQXVUcUFSczJBcnpwQVFKQUlBRkZEUUFnQlNnQ3JPa0JJZ2tnSFVZTkFDQUZJQWsyQXJqcEFTQUZJQjAyQXF6cEFTQUZLQUt3NlFFaERpQUZJQjAyQXJEcEFTQUZJQjBnRGlBSmEybzJBclRwQVF0QnVIOGhDU0FEUVFWQkNTQUZLQUxrNmdFaUJodEpEUVVnQWtFQlFRVWdCaHNnQmhBYUlnNUJpSDlMQkVBZ0RpRUpEQVVMSUFNZ0RrRURha2tOQlNBcElBSWdEaUFHRUJraUJrR0lmMHNFUUNBR0lRa01CUXNnQmcwRkFrQUNRQ0FGS0FLbzZ3RkJBVWNOQUNBRktBS2s2d0VpQ1VVTkFDQUZLQUtVNndGRkRRQWdDU2dDQkVFQmF5SUhJQVVvQXR6cEFTSUtyVUtIbGErdm1MYmVtNTUvZmtMSno5bXk4ZVc2NmllRlFoZUpRcy9XMDc3U3g2dlpRbjVDK2ZQZDhabjJtYXNXZkNJL1FpR0lJRCtGUXMvVzA3N1N4NnZaUW40aVAwSWRpQ0EvaFVMNTg5M3htZmFacXhaK0lqOUNJSWdnUDRXbmNTRUdJQWtvQWdBaEZRTkFRUUFoQ0FKQUlCVWdCa0VDZEdvb0FnQWlDVVVOQUNBSktBSUlRUWhKRFFBZ0NTZ0NCQ0lTS0FBQVFiZkl3dUYrUncwQUlCSW9BQVFoQ0FzZ0NDQUtSd1JBSUFZZ0IzRkJBV29oQmlBSURRRUxDeUFKUlEwQUlBVVFHQ0FGUVg4MkFxRHJBU0FGSUFrMkFwVHJBU0FGSUFVb0F0enBBU0lJTmdLWTZ3RU1BUXNnQlNnQzNPa0JJUWdMQWtBZ0NFVU5BQ0FGS0FLWTZ3RWdDRVlOQUVGZ0lRa01CZ3NDUUNBRktBTGc2UUVFUUNBRklBVW9BdWpxQVNJSlJUWUM3T29CSUFrTkFTQUZRdm5xME5EbnlhSGs0UUEzQTZqcUFTQUZRZ0EzQTZEcUFTQUZRcy9XMDc3U3g2dlpRamNEbU9vQklBVkMxdXVDN3VyOWlmWGdBRGNEa09vQklBVkNBRGNEaU9vQklDSkJBRUVvRUFNYURBRUxJQVZCQURZQzdPb0JDeUFCSUIxcUlTVWdCU0FGS1FQbzZRRWdEcTE4TndQbzZRRWdBeUFPYXlFRElBSWdEbW9oQWlBZElRNERRQ0FDSUFNZ0JFRXNhaEFkSWhWQmlIOUxCRUFnRlNFSkRBWUxJQU5CQTJzaU5TQVZTUTBFSUFKQkEyb2hHMEZzSVFrQ1FBSkFBa0FDUUFKQUFrQUNRQUpBQWtBQ1FBSkFBa0FDUUFKQUFrQUNRQ0FFS0FJc0RnTUNBUUFWQ3lBVlFmLy9CMHNORXlBVlFRTkpEUklnQlNrRHlPa0JJVDhDUUFKQUlCc3RBQUFpQ1VFRGNTSWFRUUZyRGdNR0FRQUhDeUFGS0FLQTZnRU5BRUZpSVFrTUZRc2dGVUVGU1EwU0lCc29BQUFoQXdKL0FrQUNRQUpBSUFsQkFuWkJBM0VpQ1VFQ2F3NENBUUlBQ3lBSlFRQkhJUWNnQTBFRWRrSC9CM0VoQzBFRElRWWdBMEVPZGtIL0IzRU1BZ3RCQkNFR0lBTkJCSFpCLy84QWNTRUxRUUVoQnlBRFFSSjJEQUVMSUFOQkJIWkIvLzhQY1NJTFFZQ0FDRXNORTBFQklRZEJCU0VHSUFJdEFBZEJDblFnQTBFV2RuSUxJZ2dnQm1vaUNTQVZTdzBTQWtBZ0MwR0JCa2tOQUNBRktBS2M2d0ZGRFFCQkFDRURBMEFnQTBHRGdBRkxEUUVnQTBGQWF5RUREQUFMQUFzZ0JpQWJhaUVQSUJwQkEwY05CaUFGS0FJTUlnSXRBQUZCQ0hRaEF5QUhEUWNnQTBVTkNDQUVRZkFBYWlBUElBZ1FEU0lEUVloL1N3MEpJQUpCQkdvaEJpQUxJQnhxSWhKQkEyc2hDa0VBSUFJdkFRSnJRUjl4SVFjZ0hDRURBMEFnQkVId0FHb1FEMFVnQXlBS1NYRUVRQ0FESUFZZ0JDZ0NjQ0lJSUFRb0FuUWlEM1FnQjNaQkFuUnFJZ0l2QVFBN0FBQWdBeUFDTFFBRGFpSURJQVlnQ0NBUElBSXRBQUpxSWdoMElBZDJRUUowYWlJQ0x3RUFPd0FBSUFRZ0NDQUNMUUFDYWpZQ2RDQURJQUl0QUFOcUlRTU1BUVVnRWtFQ2F5RUlBMEFnQkVId0FHb1FEeUVQSUFRb0FuQWhDaUFFS0FKMElRSWdBeUFJU3lBUGNrVUVRQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lDaThCQURzQUFDQUVJQUlnQ2kwQUFtbzJBblFnQXlBS0xRQURhaUVEREFFTEN3TkFJQU1nQ0UwRVFDQURJQVlnQ2lBQ2RDQUhka0VDZEdvaUR5OEJBRHNBQUNBRElBOHRBQU5xSVFNZ0FpQVBMUUFDYWlFQ0RBRUxDd0pBSUFNZ0VrOE5BQ0FESUFZZ0NpQUNkQ0FIZGtFQ2RHb2lBeTBBQURvQUFDQURMUUFEUVFGR0JFQWdBaUFETFFBQ2FpRUNEQUVMSUFKQkgwc05BRUVnSUFJZ0F5MEFBbW9pQWlBQ1FTQlBHeUVDQzBGc1FXd2dDeUFFS0FKNElBUW9BbnhIR3lBQ1FTQkhHeUVEREFzTEFBc0FDeUFFS0FJMElnSWdKU0FPYTBzTkNpQU9SUVJBUVFBaENTQUNEUUlNRGdzZ0RpQWJMUUFBSUFJUUF4b2dBaUVKREF3TElCVWdKU0FPYTBzTkNTQU9EUUZCQUNFSklCVkZEUXdMUWJaL0lRa01FUXNnRGlBYklCVVFBaG9nRlNFSkRBb0xJQndnR3dKL0FrQUNRQUpBSUFsQkFuWkJBM0ZCQVdzT0F3RUFBZ0FMSUFsQkEzWWhBMEVCREFJTElCc3ZBQUJCQkhZaEEwRUNEQUVMSUJWQkJFa05EaUFDTHdBRElBSXRBQVZCRUhSeUlnSkJqNENBQVVzTkRpQUNRUVIySVFOQkF3c2lBbW90QUFBZ0EwRWdhaEFESVFrZ0JTQUROZ0tBNndFZ0JTQUpOZ0x3NmdFZ0FrRUJhaUVKREFVTElCVUNmd0pBQWtBQ1FDQUpRUUoyUVFOeFFRRnJEZ01CQUFJQUN5QUpRUU4ySVFOQkFRd0NDeUFiTHdBQVFRUjJJUU5CQWd3QkN5QUNMd0FESUFJdEFBVkJFSFJ5UVFSMklRTkJBd3NpQWlBRGFpSUpRU0JxU1FSQUlBa2dGVXNORFNBY0lBSWdHMm9nQXhBQ0lRSWdCU0FETmdLQTZ3RWdCU0FDTmdMdzZnRWdBaUFEYWlJQ1FnQTNBQmdnQWtJQU53QVFJQUpDQURjQUNDQUNRZ0EzQUFBTUJRc2dCU0FETmdLQTZ3RWdCU0FDSUJ0cU5nTHc2Z0VNQkFzZ0IwVUVRQ0FlSUE4Z0NDQVVFQlFpQWtHSWYwc2dBaUFJVDNJTkRDQWNJQXNnQWlBUGFpQUlJQUpySUI0UUZTRUREQU1MSUF0RklBaEZjZzBMSUF0QkNIWWlBeUFJSUF0SkJIOGdDRUVFZENBTGJnVkJEd3RCR0d3aUFrR01DR29vQWdCc0lBSkJpQWhxS0FJQWFpSUdRUU4ySUFacUlBSkJnQWhxS0FJQUlBSkJoQWhxS0FJQUlBTnNha2tFUUNNQVFSQnJJaEFrQUNBZUtBSUFJUU1nRkVId0JHcEJBRUhzQUJBRElRWkJWQ0VDQWtBZ0EwSC9BWEVpREVFTVN3MEFBa0FnRkVIY0NXb2dCaUFRUVFocUlCQkJER29nRHlBSUlCUkIzQXRxSWhjUUN5SVNRWWgvU3cwQUlCQW9BZ3dpQmlBTVN3MEJJQlJCcUFWcUlRMGdGRUdrQldvaE5pQWVRUVJxSVJFZ0EwR0FnSUI0Y1NFM0lBWkJBV29pRXlFQ0lBWWhBd05BSUFJaUIwRUJheUVDSUFNaUNrRUJheUVESUJRZ0NrRUNkR29vQXZBRVJRMEFDMEVCSUFjZ0IwRUJUUnNoRmtFQUlRZEJBU0VDQTBBZ0FpQVdSd1JBSUJRZ0FrRUNkQ0lEYWlnQzhBUWhHQ0FESUExcUlBYzJBZ0FnQWtFQmFpRUNJQWNnR0dvaEJ3d0JDd3NnRFNBSE5nSUFRUUFoQWlBUUtBSUlJUU1EUUNBQ0lBTkhCRUFnRFNBQ0lCUnFRZHdKYWkwQUFDSVlRUUowYWlJWklCa29BZ0FpR1VFQmFqWUNBQ0FVSUJsQkFYUnFJaGtnR0RvQTNRVWdHU0FDT2dEY0JTQUNRUUZxSVFJTUFRc0xRUUFoQXlBTlFRQTJBZ0FnRENBR1FYOXphaUVHUVFFaEFnTkFJQUlnRmtjRVFDQVVJQUpCQW5ScUlnMGdBellDQUNBTktBTHdCQ0FDSUFacWRDQURhaUVESUFKQkFXb2hBZ3dCQ3dzZ0RDQVRJQXBySWdaclFRRnFJUW9nQmlFREEwQWdBeUFLU1FSQUlCUWdBMEUwYkdvaERVRUJJUUlEUUNBQ0lCWkhCRUFnRFNBQ1FRSjBJaGhxSUJRZ0dHb29BZ0FnQTNZMkFnQWdBa0VCYWlFQ0RBRUxDeUFEUVFGcUlRTU1BUXNMSUJjZ0ZFRTBFQUloT0NBVVFaQU1haUU1SUJNZ0RHc2hPaUFVUWR3RmFpRVhRUUFoQ2dOQUFrQUNRQ0FISUFwSEJFQkJBU0FNSUJNZ0Z5QUtRUUYwYWlJQ0xRQUJJZzFySWdOckloaDBJUmtnQWkwQUFDRVdJRGdnRFVFQ2RHb2lIeWdDQUNFQ0lBWWdHRTBFUUNBMlFRRWdBeUE2YWlJTklBMUJBVXdiSWlCQkFuUWlKR29vQWdBaERTQTVJQlFnQTBFMGJHcEJOQkFDSVNFZ0RVRUJkQ0VtSUJFZ0FrRUNkR29oSXlBZ1FRRk5EUUlnQTBFUWRFR0FnUHdIY1NBV2NrR0FnSUFJY2lFZ0lDRWdKR29vQWdBaEpFRUFJUUlEUUNBQ0lDUkdEUU1nSXlBQ1FRSjBhaUFnTmdFQUlBSkJBV29oQWd3QUN3QUxJQUlnQWlBWmFpSU5JQUlnRFVzYklRMGdBMEVRZEVHQWdQd0hjU0FXY2tHQWdJQUljaUVEQTBBZ0FpQU5SZzBESUJFZ0FrRUNkR29nQXpZQkFDQUNRUUZxSVFJTUFBc0FDeUFlSUF4QkVIUWdOM0lnREhKQmdBSnlOZ0lBREFNTElBY2dEV3NoSkNBWElDWnFJU1pCQUNFTkEwQWdEU0FrUmcwQlFRRWdHQ0FUSUNZZ0RVRUJkR29pSnkwQUFTSUNheUk3YTNRaVBDQWhJQUpCQW5ScUlpQW9BZ0FpQW1vaFBTQURJRHRxUVJCMFFZQ0EvQWR4SUNjdEFBQkJDSFJ5SUJaeVFZQ0FnQkJ5SVNjRFFDQWpJQUpCQW5ScUlDYzJBUUFnQWtFQmFpSUNJRDFKRFFBTElDQWdJQ2dDQUNBOGFqWUNBQ0FOUVFGcUlRME1BQXNBQ3lBZklCOG9BZ0FnR1dvMkFnQWdDa0VCYWlFS0RBQUxBQXNnRWlFQ0N5QVFRUkJxSkFBZ0FrR0lmMHNnQWlBSVQzSU5EQ0FjSUFzZ0FpQVBhaUFJSUFKcklCNFFGaUVEREFNTElCNGdEeUFJSUJRUUZDSUNRWWgvU3lBQ0lBaFBjZzBMSUJ3Z0N5QUNJQTlxSUFnZ0Ftc2dIaEFYSVFNTUFnc2dBd1JBSUJ3Z0N5QVBJQWdnQWhBV0lRTU1BZ3NnSENBTElBOGdDQ0FDRUJjaEF3d0JDeUFjSUFzZ0R5QUlJQUlRRlNFREN5QURRWWgvU3cwSUlBVWdDellDZ09zQklBVWdIRFlDOE9vQklBVkJBVFlDZ09vQklCcEJBa1lFUUNBRklCNDJBZ3dMSUFzZ0hHb2lBa0lBTndBQUlBSkNBRGNBR0NBQ1FnQTNBQkFnQWtJQU53QUlJQWxCaUg5TERRb0xJQWtnRlVZTkNDQVZJQWxySVFZZ0JTZ0NuT3NCSVFvQ1FDQUpJQnRxSWdNdEFBQWlEMFVFUUVFQklRSkJBQ0VQUWJoL0lRa2dCa0VCUmcwQkRBc0xBbjhnQTBFQmFpQVB3Q0lDUVFCT0RRQWFJQUpCZjBZRVFDQUdRUU5JRFFzZ0F5OEFBVUdBL2dGcUlROGdBMEVEYWd3QkN5QUdRUUpJRFFvZ0F5MEFBU0FQUVFoMGNrR0FnQUpySVE4Z0EwRUNhZ3NoRWtHNGZ5RUpJQkpCQVdvaUFpQVZJQnRxSWdkTERRb2dMQ0FGSUJJdEFBQWlFa0VHZGtFalFRa2dBaUFISUFKclFjQVFRZEFSUWZBU0lBVW9Bb1RxQVNBS0lBOGdGQkFoSWdsQmlIOUxEUWdnS3lBb0lCSkJCSFpCQTNGQkgwRUlJQUlnQ1dvaUFpQUhJQUpyUVlBTFFZQU1RWUFYSUFVb0FvVHFBU0FGS0FLYzZ3RWdEeUFVRUNFaUNFR0lmMHNOQ0VGc0lRa2dLaUF0SUJKQkFuWkJBM0ZCTkVFSklBSWdDR29pQWlBSElBSnJRWUFOUWVBT1FaQVpJQVVvQW9UcUFTQUZLQUtjNndFZ0R5QVVFQ0VpQjBHSWYwc05DaUFDSUFkcUlBTnJJZ0loQ1NBQ1FZaC9TdzBLQ3lBT0lBOUJBRXh5RFFFTFFicC9JUWtNQ0FzZ0pTQU9heUVKSUFZZ0Ftc2hCaUFDSUFOcUlRY0NRQUpBQWtBZ0NrVUVRQ0FQUVFsSUlBVXBBOGpwQVVLQmdJQUlWSElOQWlBb0tBSUFJZ0pCQ0dvaEVpQUNLQUlFSVFwQkFDRURRUUFoQWdOQUlBTWdDblpGQkVBZ0FpQVNJQU5CQTNScUxRQUNRUlpMYWlFQ0lBTkJBV29oQXd3QkN3c2dCVUVBTmdLYzZ3RWdBa0VJSUFwcmRFRVVUdzBCREFNTElBVkJBRFlDbk9zQkN5QUVJQVVvQXZEcUFTSUROZ0xjQVNBSklBNXFJUllnQXlBRktBS0E2d0ZxSVJjQ1FDQVBSUVJBSUE0aEJ3d0JDeUFGS0FLNDZRRWhHaUFGS0FLMDZRRWhHQ0FGS0FLdzZRRWhFaUFGUVFFMkFvVHFBVUVBSVFNRFFDQURRUU5IQkVBZ0JDQURRUUowSWdKcUlBSWdCV3BCck5BQmFpZ0NBRFlDWkNBRFFRRnFJUU1NQVFzTFFXd2hDU0FFUVRocUlnSWdCeUFHRUExQmlIOUxEUU5CQ0NBUElBOUJDRTRiSVI4Z05DQUNJQVVvQWdBUUhpQXpJQUlnQlNnQ0NCQWVJRElnQWlBRktBSUVFQjRnRGlBU2F5RVpRUUFoQ0FOQUlBUkJPR29RRDBFRFJpQUlJQjlPY2tVRVFDQUVLQUpRSUFRb0FreEJBM1JxS1FJQUlrQ25JZ2RCRUhZaUVVSC9BWEVoQ3lBRUtBSmdJQVFvQWx4QkEzUnFLUUlBSWtHbklneEJFSFlpSVVIL0FYRWhFQ0FFS0FKWUlBUW9BbFJCQTNScUtRSUFJa0pDSUlpbklRWWdRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ2tIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ1BDSUtheUlOSUFJZ0FpQU5TeHNpRXlBS2FqWUNQQ0FHSUFRb0FqZ2dDblJCQUNBVGEzWWdBaUFUYXlJVGRHb2hDaUFFUVRocUVBOGFJQUlnRFUwTkFTQUVJQVFvQWp3aUFpQVRhallDUENBRUtBSTRJQUowUVFBZ0UydDJJQXBxSVFvTUFRc2dCQ0FDSUFRb0Fqd2lEV28yQWp3Z0JDZ0NPQ0FOZEVFQUlBcHJkaUFHYWlFS0lBUkJPR29RRHhvTElBUXBBbVFoUkNBRUlBbzJBbVFnQkNCRU53Sm9EQUVMQWtBZ0FrVUVRQ0FEQkVBZ0JDZ0NaQ0VLREFNTElBUW9BbWdoQ2d3QkN5QUVJQVFvQWp3aUFrRUJhallDUEFKL0lBWWdBMFZxSUFRb0FqZ2dBblJCSDNacUlnSkJBMFlFUUNBRUtBSmtRUUZyREFFTElBSkJBblFnQkdvb0FtUUxJZ1pGSUFacUlRb2dBa0VCUndSQUlBUWdCQ2dDYURZQ2JBc0xJQVFnQkNnQ1pEWUNhQ0FFSUFvMkFtUUxweUVDSUVGQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDUENJR0lCQnFOZ0k4SUFRb0FqZ2dCblJCQUNBaGEzWWdBbW9oQWdzZ0N5QVFha0VVVHdSQUlBUkJPR29RRHhvTElFQkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUdJQXRxTmdJOElBUW9BamdnQm5SQkFDQVJhM1lnQTJvaEF3c2dCRUU0YWhBUEdpQUVJQVFvQWpnaUJrRUFJQWRCR0hZaUN5QUVLQUk4YWlJUWEzWWdDMEVDZEVHZ0hXb29BZ0J4SUFkQi8vOERjV28yQWt3Z0JDQVFJQXhCR0hZaUIyb2lDellDUENBRUlBZEJBblJCb0IxcUtBSUFJQVpCQUNBTGEzWnhJQXhCLy84RGNXbzJBbHdnQkVFNGFoQVBHaUFFSUVLbklnWkJHSFlpQnlBRUtBSThhaUlMTmdJOElBUWdCMEVDZEVHZ0hXb29BZ0FnQkNnQ09FRUFJQXRyZG5FZ0JrSC8vd054YWpZQ1ZDQUVRZkFBYWlBSVFReHNhaUlHSUFvMkFnZ2dCaUFDTmdJRUlBWWdBellDQUNBSVFRRnFJUWdnQXlBWmFpQUNhaUVaREFFTEN5QUlJQjlJRFFNZ0ZrRWdheUVoSUE0aEJ3TkFJQVJCT0dvUUQwRURSaUFJSUE5T2NrVUVRQ0FFS0FKUUlBUW9Ba3hCQTNScUtRSUFJa0NuSWdaQkVIWWlJMEgvQVhFaENpQUVLQUpnSUFRb0FseEJBM1JxS1FJQUlrR25JZzFCRUhZaUlFSC9BWEVoRXlBRUtBSllJQVFvQWxSQkEzUnFLUUlBSWtKQ0lJaW5JUU1nUVVJZ2lDQkFRaUNJcHlFTEFrQWdRa0lRaUtjaURFSC9BWEVpQWtFQ1R3UkFBa0FnQWtFWlNTQS9Rb0dBZ0JCVWNrVUVRQ0FFUVNBZ0JDZ0NQQ0lNYXlJUklBSWdBaUFSU3hzaUVDQU1hallDUENBRElBUW9BamdnREhSQkFDQVFhM1lnQWlBUWF5SU1kR29oRUNBRVFUaHFFQThhSUFJZ0VVME5BU0FFSUFRb0Fqd2lBaUFNYWpZQ1BDQUVLQUk0SUFKMFFRQWdER3QySUJCcUlSQU1BUXNnQkNBQ0lBUW9BandpRUdvMkFqd2dCQ2dDT0NBUWRFRUFJQXhyZGlBRGFpRVFJQVJCT0dvUUR4b0xJQVFwQW1RaFJDQUVJQkEyQW1RZ0JDQkVOd0pvREFFTEFrQWdBa1VFUUNBTEJFQWdCQ2dDWkNFUURBTUxJQVFvQW1naEVBd0JDeUFFSUFRb0Fqd2lBa0VCYWpZQ1BBSi9JQU1nQzBWcUlBUW9BamdnQW5SQkgzWnFJZ0pCQTBZRVFDQUVLQUprUVFGckRBRUxJQUpCQW5RZ0JHb29BbVFMSWdORklBTnFJUkFnQWtFQlJ3UkFJQVFnQkNnQ2FEWUNiQXNMSUFRZ0JDZ0NaRFlDYUNBRUlCQTJBbVFMcHlFTUlFRkNnSUQ4QjROUVJRUkFJQVFnQkNnQ1BDSUNJQk5xTmdJOElBUW9BamdnQW5SQkFDQWdhM1lnREdvaERBc2dDaUFUYWtFVVR3UkFJQVJCT0dvUUR4b0xJRUJDZ0lEOEI0TlFSUVJBSUFRZ0JDZ0NQQ0lDSUFwcU5nSThJQVFvQWpnZ0FuUkJBQ0FqYTNZZ0Myb2hDd3NnQkVFNGFoQVBHaUFFSUFRb0FqZ2lBa0VBSUFaQkdIWWlBeUFFS0FJOGFpSUthM1lnQTBFQ2RFR2dIV29vQWdCeElBWkIvLzhEY1dvMkFrd2dCQ0FLSUExQkdIWWlBMm9pQmpZQ1BDQUVJQU5CQW5SQm9CMXFLQUlBSUFKQkFDQUdhM1p4SUExQi8vOERjV28yQWx3Z0JFRTRhaEFQR2lBRUlFS25JZ0pCR0hZaUF5QUVLQUk4YWlJR05nSThJQVFnQTBFQ2RFR2dIV29vQWdBZ0JDZ0NPRUVBSUFacmRuRWdBa0gvL3dOeGFqWUNWQUpBQWtBQ1FDQUVLQUxjQVNJRElBUkI4QUJxSUFoQkIzRkJER3hxSWhNb0FnQWlFV29pSXlBWFN3MEFJQWNnRXlnQ0JDSU5JQkZxSWdwcUlDRkxEUUFnQ2tFZ2FpQVdJQWRyVFEwQkN5QUVJQk1vQWdnMkFoZ2dCQ0FUS1FJQU53TVFJQWNnRmlBRVFSQnFJQVJCM0FGcUlCY2dFaUFZSUJvUUh5RUtEQUVMSUFjZ0VXb2hBaUFUS0FJSUlRWWdCeUFES1FBQU53QUFJQWNnQXlrQUNEY0FDQUpBSUJGQkVVa05BQ0FISUFNcEFCQTNBQkFnQnlBREtRQVlOd0FZSUJGQkVHdEJFVWdOQUNBRFFSQnFJUU1nQjBFZ2FpRVJBMEFnRVNBREtRQVFOd0FBSUJFZ0F5a0FHRGNBQ0NBUklBTXBBQ0EzQUJBZ0VTQURLUUFvTndBWUlBTkJJR29oQXlBUlFTQnFJaEVnQWtrTkFBc0xJQUlnQm1zaEF5QUVJQ00yQXR3QklBSWdFbXNnQmtrRVFDQUdJQUlnR0d0TERRY2dHaUFhSUFNZ0Vtc2lBMm9pRVNBTmFrOEVRQ0FDSUJFZ0RSQUtHZ3dDQ3lBRElBMXFJUTBnQWlBUlFRQWdBMnNRQ2lBRGF5RUNJQkloQXdzZ0JrRVFUd1JBSUFJZ0F5a0FBRGNBQUNBQ0lBTXBBQWczQUFnZ0RVRVJTQTBCSUFJZ0RXb2hCaUFDUVJCcUlRSURRQ0FDSUFNcEFCQTNBQUFnQWlBREtRQVlOd0FJSUFJZ0F5a0FJRGNBRUNBQ0lBTXBBQ2czQUJnZ0EwRWdhaUVESUFKQklHb2lBaUFHU1EwQUN3d0JDd0pBSUFaQkIwMEVRQ0FDSUFNdEFBQTZBQUFnQWlBRExRQUJPZ0FCSUFJZ0F5MEFBam9BQWlBQ0lBTXRBQU02QUFNZ0FpQURJQVpCQW5RaUJrSEFIbW9vQWdCcUlnTW9BQUEyQUFRZ0F5QUdRZUFlYWlnQ0FHc2hBd3dCQ3lBQ0lBTXBBQUEzQUFBTElBMUJDVWtOQUNBQ0lBMXFJUkVnQWtFSWFpSUdJQU5CQ0dvaUEydEJEMHdFUUFOQUlBWWdBeWtBQURjQUFDQURRUWhxSVFNZ0JrRUlhaUlHSUJGSkRRQU1BZ3NBQ3lBR0lBTXBBQUEzQUFBZ0JpQURLUUFJTndBSUlBMUJHVWdOQUNBQ1FSaHFJUUlEUUNBQ0lBTXBBQkEzQUFBZ0FpQURLUUFZTndBSUlBSWdBeWtBSURjQUVDQUNJQU1wQUNnM0FCZ2dBMEVnYWlFRElBSkJJR29pQWlBUlNRMEFDd3NnQ2tHSWYwc0VRQ0FLSVFrTUJnVWdFeUFRTmdJSUlCTWdERFlDQkNBVElBczJBZ0FnQ0VFQmFpRUlJQWNnQ21vaEJ5QUxJQmxxSUF4cUlSa01BZ3NBQ3dzZ0NDQVBTQTBESUFnZ0gyc2hCZ05BQWtBZ0JpQVBUZ1JBUVFBaEF3TkFJQU5CQTBZTkFpQUZJQU5CQW5RaUFtcEJyTkFCYWlBQ0lBUnFLQUprTmdJQUlBTkJBV29oQXd3QUN3QUxBa0FDUUFKQUlBUW9BdHdCSWdNZ0JFSHdBR29nQmtFSGNVRU1iR29pQ0NnQ0FDSU1haUlRSUJkTERRQWdCeUFJS0FJRUlnc2dER29pQ21vZ0lVc05BQ0FLUVNCcUlCWWdCMnRORFFFTElBUWdDQ2dDQ0RZQ0tDQUVJQWdwQWdBM0F5QWdCeUFXSUFSQklHb2dCRUhjQVdvZ0Z5QVNJQmdnR2hBZklRb01BUXNnQnlBTWFpRUNJQWdvQWdnaENDQUhJQU1wQUFBM0FBQWdCeUFES1FBSU53QUlBa0FnREVFUlNRMEFJQWNnQXlrQUVEY0FFQ0FISUFNcEFCZzNBQmdnREVFUWEwRVJTQTBBSUFOQkVHb2hBeUFIUVNCcUlRd0RRQ0FNSUFNcEFCQTNBQUFnRENBREtRQVlOd0FJSUF3Z0F5a0FJRGNBRUNBTUlBTXBBQ2czQUJnZ0EwRWdhaUVESUF4QklHb2lEQ0FDU1EwQUN3c2dBaUFJYXlFRElBUWdFRFlDM0FFZ0FpQVNheUFJU1FSQUlBZ2dBaUFZYTBzTkJ5QWFJQm9nQXlBU2F5SURhaUlNSUF0cVR3UkFJQUlnRENBTEVBb2FEQUlMSUFNZ0Myb2hDeUFDSUF4QkFDQURheEFLSUFOcklRSWdFaUVEQ3lBSVFSQlBCRUFnQWlBREtRQUFOd0FBSUFJZ0F5a0FDRGNBQ0NBTFFSRklEUUVnQWlBTGFpRUlJQUpCRUdvaEFnTkFJQUlnQXlrQUVEY0FBQ0FDSUFNcEFCZzNBQWdnQWlBREtRQWdOd0FRSUFJZ0F5a0FLRGNBR0NBRFFTQnFJUU1nQWtFZ2FpSUNJQWhKRFFBTERBRUxBa0FnQ0VFSFRRUkFJQUlnQXkwQUFEb0FBQ0FDSUFNdEFBRTZBQUVnQWlBRExRQUNPZ0FDSUFJZ0F5MEFBem9BQXlBQ0lBTWdDRUVDZENJSVFjQWVhaWdDQUdvaUF5Z0FBRFlBQkNBRElBaEI0QjVxS0FJQWF5RUREQUVMSUFJZ0F5a0FBRGNBQUFzZ0MwRUpTUTBBSUFJZ0Myb2hEQ0FDUVFocUlnZ2dBMEVJYWlJRGEwRVBUQVJBQTBBZ0NDQURLUUFBTndBQUlBTkJDR29oQXlBSVFRaHFJZ2dnREVrTkFBd0NDd0FMSUFnZ0F5a0FBRGNBQUNBSUlBTXBBQWczQUFnZ0MwRVpTQTBBSUFKQkdHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUF4SkRRQUxDeUFLUVloL1N3UkFJQW9oQ1F3R0JTQUdRUUZxSVFZZ0J5QUthaUVIREFJTEFBc0xJQVFvQXR3QklRTUxRYnAvSVFrZ0Z5QURheUlDSUJZZ0IydExEUUlnQndSL0lBY2dBeUFDRUFJZ0Ftb0ZRUUFMSUE1cklRa01BZ3NnQlVFQU5nS2M2d0VMSUFRZ0JTZ0M4T29CSWdNMkF0d0JJQWtnRG1vaERDQURJQVVvQW9EckFXb2hFQUpBSUE5RkJFQWdEaUVHREFFTElBVW9BcmpwQVNFTklBVW9BclRwQVNFVElBVW9BckRwQVNFU0lBVkJBVFlDaE9vQlFRQWhBd05BSUFOQkEwY0VRQ0FFSUFOQkFuUWlBbW9nQWlBRmFrR3MwQUZxS0FJQU5nS2NBU0FEUVFGcUlRTU1BUXNMUVd3aENTQUVRZkFBYWlJQ0lBY2dCaEFOUVloL1N3MEJJREVnQWlBRktBSUFFQjRnTUNBQ0lBVW9BZ2dRSGlBdklBSWdCU2dDQkJBZUlBeEJJR3NoR0NBT0lRWURRQ0FFS0FLSUFTQUVLQUtFQVVFRGRHb3BBZ0FpUUtjaUNrRVFkaUlaUWY4QmNTRUxJQVFvQXBnQklBUW9BcFFCUVFOMGFpa0NBQ0pCcHlJV1FSQjJJaDlCL3dGeElSb2dCQ2dDa0FFZ0JDZ0NqQUZCQTNScUtRSUFJa0pDSUlpbklRY2dRVUlnaUNCQVFpQ0lweUVEQWtBZ1FrSVFpS2NpQ0VIL0FYRWlBa0VDVHdSQUFrQWdBa0VaU1NBL1FvR0FnQkJVY2tVRVFDQUVRU0FnQkNnQ2RDSUlheUlSSUFJZ0FpQVJTeHNpRnlBSWFqWUNkQ0FISUFRb0FuQWdDSFJCQUNBWGEzWWdBaUFYYXlJWGRHb2hDQ0FFUWZBQWFoQVBHaUFDSUJGTkRRRWdCQ0FFS0FKMElnSWdGMm8yQW5RZ0JDZ0NjQ0FDZEVFQUlCZHJkaUFJYWlFSURBRUxJQVFnQWlBRUtBSjBJaEZxTmdKMElBUW9BbkFnRVhSQkFDQUlhM1lnQjJvaENDQUVRZkFBYWhBUEdnc2dCQ2tDbkFFaFJDQUVJQWcyQXB3QklBUWdSRGNDb0FFTUFRc0NRQ0FDUlFSQUlBTUVRQ0FFS0FLY0FTRUlEQU1MSUFRb0FxQUJJUWdNQVFzZ0JDQUVLQUowSWdKQkFXbzJBblFDZnlBSElBTkZhaUFFS0FKd0lBSjBRUjkyYWlJQ1FRTkdCRUFnQkNnQ25BRkJBV3NNQVFzZ0FrRUNkQ0FFYWlnQ25BRUxJZ2RGSUFkcUlRZ2dBa0VCUndSQUlBUWdCQ2dDb0FFMkFxUUJDd3NnQkNBRUtBS2NBVFlDb0FFZ0JDQUlOZ0tjQVF1bklRSWdRVUtBZ1B3SGcxQkZCRUFnQkNBRUtBSjBJZ2NnR21vMkFuUWdCQ2dDY0NBSGRFRUFJQjlyZGlBQ2FpRUNDeUFMSUJwcVFSUlBCRUFnQkVId0FHb1FEeG9MSUVCQ2dJRDhCNE5RUlFSQUlBUWdCQ2dDZENJSElBdHFOZ0owSUFRb0FuQWdCM1JCQUNBWmEzWWdBMm9oQXdzZ0JFSHdBR29RRHhvZ0JDQUVLQUp3SWdkQkFDQUtRUmgySWdzZ0JDZ0NkR29pR210MklBdEJBblJCb0IxcUtBSUFjU0FLUWYvL0EzRnFOZ0tFQVNBRUlCb2dGa0VZZGlJS2FpSUxOZ0owSUFRZ0NrRUNkRUdnSFdvb0FnQWdCMEVBSUF0cmRuRWdGa0gvL3dOeGFqWUNsQUVnQkVId0FHb1FEeG9nQkNCQ3B5SUhRUmgySWdvZ0JDZ0NkR29pQ3pZQ2RDQUVJQXBCQW5SQm9CMXFLQUlBSUFRb0FuQkJBQ0FMYTNaeElBZEIvLzhEY1dvMkFvd0JJQVFnQXpZQ09DQUVJQUkyQWp3Z0JDQUlOZ0pBQWtBQ1FBSkFJQVFvQXR3Qklnc2dBMm9pRmlBUVN3MEFJQVlnQWlBRGFpSUthaUFZU3cwQUlBcEJJR29nRENBR2EwME5BUXNnQkNBRVFVQnJLQUlBTmdJSUlBUWdCQ2tET0RjREFDQUdJQXdnQkNBRVFkd0JhaUFRSUJJZ0V5QU5FQjhoQ2d3QkN5QURJQVpxSVFjZ0JpQUxLUUFBTndBQUlBWWdDeWtBQ0RjQUNBSkFJQU5CRVVrTkFDQUdJQXNwQUJBM0FCQWdCaUFMS1FBWU53QVlJQU5CRUd0QkVVZ05BQ0FMUVJCcUlRTWdCa0VnYWlFTEEwQWdDeUFES1FBUU53QUFJQXNnQXlrQUdEY0FDQ0FMSUFNcEFDQTNBQkFnQ3lBREtRQW9Od0FZSUFOQklHb2hBeUFMUVNCcUlnc2dCMGtOQUFzTElBY2dDR3NoQXlBRUlCWTJBdHdCSUFjZ0Vtc2dDRWtFUUNBSUlBY2dFMnRMRFFRZ0RTQU5JQU1nRW1zaUEyb2lDeUFDYWs4RVFDQUhJQXNnQWhBS0dnd0NDeUFISUF0QkFDQURheEFLSUFRZ0FpQURhaUlDTmdJOElBTnJJUWNnRWlFREN5QUlRUkJQQkVBZ0J5QURLUUFBTndBQUlBY2dBeWtBQ0RjQUNDQUNRUkZJRFFFZ0FpQUhhaUVJSUFkQkVHb2hBZ05BSUFJZ0F5a0FFRGNBQUNBQ0lBTXBBQmczQUFnZ0FpQURLUUFnTndBUUlBSWdBeWtBS0RjQUdDQURRU0JxSVFNZ0FrRWdhaUlDSUFoSkRRQUxEQUVMQWtBZ0NFRUhUUVJBSUFjZ0F5MEFBRG9BQUNBSElBTXRBQUU2QUFFZ0J5QURMUUFDT2dBQ0lBY2dBeTBBQXpvQUF5QUhJQU1nQ0VFQ2RDSUlRY0FlYWlnQ0FHb2lBeWdBQURZQUJDQURJQWhCNEI1cUtBSUFheUVEREFFTElBY2dBeWtBQURjQUFBc2dBa0VKU1EwQUlBSWdCMm9oQ3lBSFFRaHFJZ2dnQTBFSWFpSURhMEVQVEFSQUEwQWdDQ0FES1FBQU53QUFJQU5CQ0dvaEF5QUlRUWhxSWdnZ0Mwa05BQXdDQ3dBTElBZ2dBeWtBQURjQUFDQUlJQU1wQUFnM0FBZ2dBa0VaU0EwQUlBZEJHR29oQWdOQUlBSWdBeWtBRURjQUFDQUNJQU1wQUJnM0FBZ2dBaUFES1FBZ053QVFJQUlnQXlrQUtEY0FHQ0FEUVNCcUlRTWdBa0VnYWlJQ0lBdEpEUUFMQ3lBS1FZaC9Td1JBSUFvaENRd0RDeUFHSUFwcUlRWWdCRUh3QUdvUUR5RURJQTlCQVdzaUR3MEFDMEVBSVFJZ0EwRUNTUTBCQTBBZ0FrRURSd1JBSUFVZ0FrRUNkQ0lEYWtHczBBRnFJQU1nQkdvb0Fwd0JOZ0lBSUFKQkFXb2hBZ3dCQ3dzZ0JDZ0MzQUVoQXd0QnVuOGhDU0FRSUFOcklnSWdEQ0FHYTBzTkFDQUdCSDhnQmlBRElBSVFBaUFDYWdWQkFBc2dEbXNoQ1FzZ0NVR0lmMHNOQmdzQ1FDQUZLQUxzNmdGRkRRQWdCU0FGS1FPSTZnRWdDYTE4TndPSTZnRUNRQ0FGS0FMUTZnRWlBaUFKYWlJSVFSOU5CRUFnRGtVTkFTQUNJQ0pxSUE0Z0NSQUNHaUFGS0FMUTZnRWdDV29oQ0F3QkN5QU9JUU1nQWdSQUlBSWdJbW9nQTBFZ0lBSnJFQUlhSUFVb0F0RHFBU0VDSUFWQkFEWUMwT29CSUFVZ0JTa0RrT29CSUFVcEFMRHFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEa09vQklBVWdCU2tEbU9vQklBVXBBTGpxQVVMUDF0Tyswc2VyMlVKK2ZFSWZpVUtIbGErdm1MYmVtNTUvZmpjRG1Pb0JJQVVnQlNrRG9Pb0JJQVVwQU1EcUFVTFAxdE8rMHNlcjJVSitmRUlmaVVLSGxhK3ZtTGJlbTU1L2ZqY0RvT29CSUFVZ0JTa0RxT29CSUFVcEFNanFBVUxQMXRPKzBzZXIyVUorZkVJZmlVS0hsYSt2bUxiZW01NS9mamNEcU9vQklBTWdBbXRCSUdvaEF3c2dDU0FPYWlJQ0lBTkJJR3BQQkVBZ0FrRWdheUVHSUFVcEE2anFBU0UvSUFVcEE2RHFBU0ZBSUFVcEE1anFBU0ZCSUFVcEE1RHFBU0ZDQTBBZ0F5a0FHRUxQMXRPKzBzZXIyVUorSUQ5OFFoK0pRb2VWcjYrWXR0NmJubjkrSVQ4Z0F5a0FFRUxQMXRPKzBzZXIyVUorSUVCOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVBZ0F5a0FDRUxQMXRPKzBzZXIyVUorSUVGOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVFZ0F5a0FBRUxQMXRPKzBzZXIyVUorSUVKOFFoK0pRb2VWcjYrWXR0NmJubjkrSVVJZ0EwRWdhaUlESUFaTkRRQUxJQVVnUHpjRHFPb0JJQVVnUURjRG9Pb0JJQVVnUVRjRG1Pb0JJQVVnUWpjRGtPb0JDeUFDSUFOTkRRRWdJaUFESUFJZ0Eyc2lDQkFDR2dzZ0JTQUlOZ0xRNmdFTElEVWdGV3NoQXlBVklCdHFJUUlnQ1NBT2FpRU9JQVFvQWpCRkRRQUxJQ2twQXdBaVAwSi9VU0EvSUE0Z0hXdXNVWEpGQkVCQmJDRUpEQVlMSUFVb0F1RHBBUVJBUVdvaENTQURRUVJKRFFZZ0JTZ0M2T29CUlFSQUlDSWdCU2dDME9vQmFpRUtBbjRnQlNrRGlPb0JJajlDSUZvRVFDQUZLUU9ZNmdFaVFFSUhpU0FGS1FPUTZnRWlRVUlCaVh3Z0JTa0RvT29CSWtKQ0RJbDhJQVVwQTZqcUFTSkRRaEtKZkNCQlFzL1cwNzdTeDZ2WlFuNUNINGxDaDVXdnI1aTIzcHVlZjM2RlFvZVZyNitZdHQ2Ym5uOStRcDJqdGVxRHNZMksrZ0I5SUVCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZm9WQ2g1V3ZyNWkyM3B1ZWYzNUNuYU8xNm9PeGpZcjZBSDBnUWtMUDF0Tyswc2VyMlVKK1FoK0pRb2VWcjYrWXR0NmJubjkraFVLSGxhK3ZtTGJlbTU1L2ZrS2RvN1hxZzdHTml2b0FmU0JEUXMvVzA3N1N4NnZaUW41Q0g0bENoNVd2cjVpMjNwdWVmMzZGUW9lVnI2K1l0dDZibm45K1FwMmp0ZXFEc1kySytnQjlEQUVMSUFVcEE2RHFBVUxGejlteThlVzY2aWQ4Q3lBL2ZDRS9JQ0loQmdOQUlBb2dCa0VJYWlJSFR3UkFJQVlwQUFCQ3o5YlR2dExIcTlsQ2ZrSWZpVUtIbGErdm1MYmVtNTUvZmlBL2hVSWJpVUtIbGErdm1MYmVtNTUvZmtLZG83WHFnN0dOaXZvQWZTRS9JQWNoQmd3QkN3c0NRQ0FLSUFaQkJHb2lDRWtFUUNBR0lRZ01BUXNnQmpVQUFFS0hsYSt2bUxiZW01NS9maUEvaFVJWGlVTFAxdE8rMHNlcjJVSitRdm56M2ZHWjlwbXJGbndoUHdzRFFDQUlJQXBKQkVBZ0NERUFBRUxGejlteThlVzY2aWQrSUQrRlFndUpRb2VWcjYrWXR0NmJubjkrSVQ4Z0NFRUJhaUVJREFFTEN5QUNLQUFBSUQ5Q0lZZ2dQNFZDejliVHZ0TEhxOWxDZmlJL1FoMklJRCtGUXZuejNmR1o5cG1yRm40aVAwSWdpQ0EvaGFkSERRY0xJQU5CQkdzaEF5QUNRUVJxSVFJTElBNGdIV3NpQ1VHSmYwOE5CQ0FCSUFscklRRWdDU0FkYWlFZFFRRWhQZ3dCQ3d0QnVIOGhCeUFERFFRZ0hTQUFheUVIREFRTFFXd2hDUXdCQzBHNGZ5RUpDMEc0ZnlFSElBbEJka1lnUG5FTkFRc2dDU0VIQ3lnQ0FBMEFJQVZCL09vQmFpZ0NBQ0VCSUFWQitPb0JhaWdDQUNFQUlBVVFHQ0FGS0FLdzZ3RWdBQ0FCRUJNZ0JVRUFOZ0t3NndFZ0JTZ0NwT3NCSWdJRVFBSkFBa0FDUUFKQUlBSW9BZ0FpQXdSQUlBQkZEUUlnQVNBRElBQVJBZ0FNQVFzZ0FFVU5BZ3NnQVNBQ0lBQVJBZ0FNQWdzZ0F4QUdDeUFDRUFZTElBVkJBRFlDcE9zQkN5QUFCRUFnQVNBRklBQVJBZ0FNQVFzZ0JSQUdDeUFFUWVBQmFpUUFJQWNMQzZnVkNRQkJpQWdMRFFFQUFBQUJBQUFBQWdBQUFBSUFRYUFJQzdNR0FRQUFBQUVBQUFBQ0FBQUFBZ0FBQUNZQUFBQ0NBQUFBSVFVQUFFb0FBQUJuQ0FBQUpnQUFBTUFCQUFDQUFBQUFTUVVBQUVvQUFBQytDQUFBS1FBQUFDd0NBQUNBQUFBQVNRVUFBRW9BQUFDK0NBQUFMd0FBQU1vQ0FBQ0FBQUFBaWdVQUFFb0FBQUNFQ1FBQU5RQUFBSE1EQUFDQUFBQUFuUVVBQUVvQUFBQ2dDUUFBUFFBQUFJRURBQUNBQUFBQTZ3VUFBRXNBQUFBK0NnQUFSQUFBQUo0REFBQ0FBQUFBVFFZQUFFc0FBQUNxQ2dBQVN3QUFBTE1EQUFDQUFBQUF3UVlBQUUwQUFBQWZEUUFBVFFBQUFGTUVBQUNBQUFBQUl3Z0FBRkVBQUFDbUR3QUFWQUFBQUprRUFBQ0FBQUFBU3drQUFGY0FBQUN4RWdBQVdBQUFBTm9FQUFDQUFBQUFid2tBQUYwQUFBQWpGQUFBVkFBQUFFVUZBQUNBQUFBQVZBb0FBR29BQUFDTUZBQUFhZ0FBQUs4RkFBQ0FBQUFBZGdrQUFId0FBQUJPRUFBQWZBQUFBTklDQUFDQUFBQUFZd2NBQUpFQUFBQ1FCd0FBa2dBQUFBQUFBQUFCQUFBQUFRQUFBQVVBQUFBTkFBQUFIUUFBQUQwQUFBQjlBQUFBL1FBQUFQMEJBQUQ5QXdBQS9RY0FBUDBQQUFEOUh3QUEvVDhBQVAxL0FBRDkvd0FBL2Y4QkFQMy9Bd0Q5L3djQS9mOFBBUDMvSHdEOS96OEEvZjkvQVAzLy93RDkvLzhCL2YvL0EvMy8vd2Y5Ly84UC9mLy9ILzMvL3ovOS8vOS9BQUFBQUFFQUFBQUNBQUFBQXdBQUFBUUFBQUFGQUFBQUJnQUFBQWNBQUFBSUFBQUFDUUFBQUFvQUFBQUxBQUFBREFBQUFBMEFBQUFPQUFBQUR3QUFBQkFBQUFBUkFBQUFFZ0FBQUJNQUFBQVVBQUFBRlFBQUFCWUFBQUFYQUFBQUdBQUFBQmtBQUFBYUFBQUFHd0FBQUJ3QUFBQWRBQUFBSGdBQUFCOEFBQUFEQUFBQUJBQUFBQVVBQUFBR0FBQUFCd0FBQUFnQUFBQUpBQUFBQ2dBQUFBc0FBQUFNQUFBQURRQUFBQTRBQUFBUEFBQUFFQUFBQUJFQUFBQVNBQUFBRXdBQUFCUUFBQUFWQUFBQUZnQUFBQmNBQUFBWUFBQUFHUUFBQUJvQUFBQWJBQUFBSEFBQUFCMEFBQUFlQUFBQUh3QUFBQ0FBQUFBaEFBQUFJZ0FBQUNNQUFBQWxBQUFBSndBQUFDa0FBQUFyQUFBQUx3QUFBRE1BQUFBN0FBQUFRd0FBQUZNQUFBQmpBQUFBZ3dBQUFBTUJBQUFEQWdBQUF3UUFBQU1JQUFBREVBQUFBeUFBQUFOQUFBQURnQUFBQXdBQkFFSGdEd3RSQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQkFBQUFBVUFBQUFIQUFBQUNBQUFBQWtBQUFBS0FBQUFDd0FBQUF3QUFBQU5BQUFBRGdBQUFBOEFBQUFRQUVIRUVBdUxBUUVBQUFBQ0FBQUFBd0FBQUFRQUFBQUZBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFTQUFBQUZBQUFBQllBQUFBWUFBQUFIQUFBQUNBQUFBQW9BQUFBTUFBQUFFQUFBQUNBQUFBQUFBRUFBQUFDQUFBQUJBQUFBQWdBQUFBUUFBQUFJQUFBQUVBQUFBQ0FBQUFBQUFFQVFaQVNDK1lFQVFBQUFBRUFBQUFCQUFBQUFRQUFBQUlBQUFBQ0FBQUFBd0FBQUFNQUFBQUVBQUFBQmdBQUFBY0FBQUFJQUFBQUNRQUFBQW9BQUFBTEFBQUFEQUFBQUEwQUFBQU9BQUFBRHdBQUFCQUFBQUFCQUFBQUJBQUFBQWdBQUFBQUFBQUFBUUFCQVFZQUFBQUFBQUFFQUFBQUFCQUFBQVFBQUFBQUlBQUFCUUVBQUFBQUFBQUZBd0FBQUFBQUFBVUVBQUFBQUFBQUJRWUFBQUFBQUFBRkJ3QUFBQUFBQUFVSkFBQUFBQUFBQlFvQUFBQUFBQUFGREFBQUFBQUFBQVlPQUFBQUFBQUJCUkFBQUFBQUFBRUZGQUFBQUFBQUFRVVdBQUFBQUFBQ0JSd0FBQUFBQUFNRklBQUFBQUFBQkFVd0FBQUFJQUFHQlVBQUFBQUFBQWNGZ0FBQUFBQUFDQVlBQVFBQUFBQUtCZ0FFQUFBQUFBd0dBQkFBQUNBQUFBUUFBQUFBQUFBQUJBRUFBQUFBQUFBRkFnQUFBQ0FBQUFVRUFBQUFBQUFBQlFVQUFBQWdBQUFGQndBQUFBQUFBQVVJQUFBQUlBQUFCUW9BQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBSUFBQkJSQUFBQUFBQUFFRkVnQUFBQ0FBQVFVV0FBQUFBQUFDQlJnQUFBQWdBQU1GSUFBQUFBQUFBd1VvQUFBQUFBQUdCRUFBQUFBUUFBWUVRQUFBQUNBQUJ3V0FBQUFBQUFBSkJnQUNBQUFBQUFzR0FBZ0FBREFBQUFRQUFBQUFFQUFBQkFFQUFBQWdBQUFGQWdBQUFDQUFBQVVEQUFBQUlBQUFCUVVBQUFBZ0FBQUZCZ0FBQUNBQUFBVUlBQUFBSUFBQUJRa0FBQUFnQUFBRkN3QUFBQ0FBQUFVTUFBQUFBQUFBQmc4QUFBQWdBQUVGRWdBQUFDQUFBUVVVQUFBQUlBQUNCUmdBQUFBZ0FBSUZIQUFBQUNBQUF3VW9BQUFBSUFBRUJUQUFBQUFBQUJBR0FBQUJBQUFBRHdZQWdBQUFBQUFPQmdCQUFBQUFBQTBHQUNBQVFZQVhDNGNDQVFBQkFRVUFBQUFBQUFBRkFBQUFBQUFBQmdROUFBQUFBQUFKQmYwQkFBQUFBQThGL1g4QUFBQUFGUVg5L3g4QUFBQURCUVVBQUFBQUFBY0VmUUFBQUFBQURBWDlEd0FBQUFBU0JmMy9Bd0FBQUJjRi9mOS9BQUFBQlFVZEFBQUFBQUFJQlAwQUFBQUFBQTRGL1Q4QUFBQUFGQVg5L3c4QUFBQUNCUUVBQUFBUUFBY0VmUUFBQUFBQUN3WDlCd0FBQUFBUkJmMy9BUUFBQUJZRi9mOC9BQUFBQkFVTkFBQUFFQUFJQlAwQUFBQUFBQTBGL1I4QUFBQUFFd1g5L3djQUFBQUJCUUVBQUFBUUFBWUVQUUFBQUFBQUNnWDlBd0FBQUFBUUJmMy9BQUFBQUJ3Ri9mLy9Ed0FBR3dYOS8vOEhBQUFhQmYzLy93TUFBQmtGL2YvL0FRQUFHQVg5Ly84QVFaQVpDNFlFQVFBQkFRWUFBQUFBQUFBR0F3QUFBQUFBQUFRRUFBQUFJQUFBQlFVQUFBQUFBQUFGQmdBQUFBQUFBQVVJQUFBQUFBQUFCUWtBQUFBQUFBQUZDd0FBQUFBQUFBWU5BQUFBQUFBQUJoQUFBQUFBQUFBR0V3QUFBQUFBQUFZV0FBQUFBQUFBQmhrQUFBQUFBQUFHSEFBQUFBQUFBQVlmQUFBQUFBQUFCaUlBQUFBQUFBRUdKUUFBQUFBQUFRWXBBQUFBQUFBQ0JpOEFBQUFBQUFNR093QUFBQUFBQkFaVEFBQUFBQUFIQm9NQUFBQUFBQWtHQXdJQUFCQUFBQVFFQUFBQUFBQUFCQVVBQUFBZ0FBQUZCZ0FBQUFBQUFBVUhBQUFBSUFBQUJRa0FBQUFBQUFBRkNnQUFBQUFBQUFZTUFBQUFBQUFBQmc4QUFBQUFBQUFHRWdBQUFBQUFBQVlWQUFBQUFBQUFCaGdBQUFBQUFBQUdHd0FBQUFBQUFBWWVBQUFBQUFBQUJpRUFBQUFBQUFFR0l3QUFBQUFBQVFZbkFBQUFBQUFDQmlzQUFBQUFBQU1HTXdBQUFBQUFCQVpEQUFBQUFBQUZCbU1BQUFBQUFBZ0dBd0VBQUNBQUFBUUVBQUFBTUFBQUJBUUFBQUFRQUFBRUJRQUFBQ0FBQUFVSEFBQUFJQUFBQlFnQUFBQWdBQUFGQ2dBQUFDQUFBQVVMQUFBQUFBQUFCZzRBQUFBQUFBQUdFUUFBQUFBQUFBWVVBQUFBQUFBQUJoY0FBQUFBQUFBR0dnQUFBQUFBQUFZZEFBQUFBQUFBQmlBQUFBQUFBQkFHQXdBQkFBQUFEd1lEZ0FBQUFBQU9CZ05BQUFBQUFBMEdBeUFBQUFBQURBWURFQUFBQUFBTEJnTUlBQUFBQUFvR0F3UUFRYVFkQzlrQkFRQUFBQU1BQUFBSEFBQUFEd0FBQUI4QUFBQS9BQUFBZndBQUFQOEFBQUQvQVFBQS93TUFBUDhIQUFEL0R3QUEveDhBQVA4L0FBRC9md0FBLy84QUFQLy9BUUQvL3dNQS8vOEhBUC8vRHdELy94OEEvLzgvQVAvL2Z3RC8vLzhBLy8vL0FmLy8vd1AvLy84SC8vLy9ELy8vL3gvLy8vOC8vLy8vZndBQUFBQUJBQUFBQWdBQUFBUUFBQUFBQUFBQUFnQUFBQVFBQUFBSUFBQUFBQUFBQUFFQUFBQUNBQUFBQVFBQUFBUUFBQUFFQUFBQUJBQUFBQVFBQUFBSUFBQUFDQUFBQUFnQUFBQUhBQUFBQ0FBQUFBa0FBQUFLQUFBQUN3QkJnQjhMQTRBUkFRPT0iO3ZhciB0dD1uZXcgR0EsSXQ9ITE7YXN5bmMgZnVuY3Rpb24gREkoQSxlKXtsZXQgdD1udWxsO3R5cGVvZiBBIT0ic3RyaW5nIj90PUEuaHJlZjpBLnN0YXJ0c1dpdGgoImh0dHAiKT90PUE6dD1gJHtlfS8ke0F9YCx0LmVuZHNXaXRoKCIuanMiKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC0zKSksdC5lbmRzV2l0aCgiLndhc20iKSYmKHQ9dC5zdWJzdHJpbmcoMCx0Lmxlbmd0aC01KSk7bGV0IEk9YCR7dH0ud2FzbWAscj1hd2FpdCBSQS5nZXQoYCR7SX0uenN0YCx7cmVzcG9uc2VUeXBlOiJhcnJheWJ1ZmZlciJ9KTtJdHx8KGF3YWl0IHR0LmluaXQoKSxJdD0hMCk7bGV0IGc9dHQuZGVjb2RlKG5ldyBVaW50OEFycmF5KHIuZGF0YSkpLmJ1ZmZlcjtyZXR1cm4oYXdhaXQgaW1wb3J0KGAke3R9LmpzYCkpLmRlZmF1bHQoe3dhc21CaW5hcnk6Z30pfXZhciBydD1ESTt2YXIgVUE9bmV3IE1hcDthc3luYyBmdW5jdGlvbiB5SShBLGUpe2xldCB0PUEsST1BLHI9bnVsbDtyZXR1cm4gdHlwZW9mIEEhPSJzdHJpbmciJiYodD1uZXcgVVJMKEEuaHJlZiksST10LmhyZWYpLFVBLmhhcyhJKXx8VUEuc2V0KEksYXdhaXQgcnQodCxlKSkscj1VQS5nZXQoSSkscn12YXIgRz15STt2YXIgd0k9bmV3IE1hcChbWyJpbWFnZS9qcGVnIiwiSlBFR0ltYWdlSU8iXSxbImltYWdlL3BuZyIsIlBOR0ltYWdlSU8iXSxbImltYWdlL3RpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiaW1hZ2UveC1tcy1ibXAiLCJCTVBJbWFnZUlPIl0sWyJpbWFnZS94LWJtcCIsIkJNUEltYWdlSU8iXSxbImltYWdlL2JtcCIsIkJNUEltYWdlSU8iXSxbImFwcGxpY2F0aW9uL2RpY29tIiwiR0RDTUltYWdlSU8iXV0pLGllPXdJO3ZhciBwST1uZXcgTWFwKFtbImJtcCIsIkJNUEltYWdlSU8iXSxbIkJNUCIsIkJNUEltYWdlSU8iXSxbImRjbSIsIkdEQ01JbWFnZUlPIl0sWyJEQ00iLCJHRENNSW1hZ2VJTyJdLFsiZ2lwbCIsIkdpcGxJbWFnZUlPIl0sWyJnaXBsLmd6IiwiR2lwbEltYWdlSU8iXSxbImhkZjUiLCJIREY1SW1hZ2VJTyJdLFsianBnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRyIsIkpQRUdJbWFnZUlPIl0sWyJqcGVnIiwiSlBFR0ltYWdlSU8iXSxbIkpQRUciLCJKUEVHSW1hZ2VJTyJdLFsiaXdpIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yIiwiV2FzbUltYWdlSU8iXSxbIml3aS5jYm9yLnpzdCIsIldhc21ac3RkSW1hZ2VJTyJdLFsibHNtIiwiTFNNSW1hZ2VJTyJdLFsibW5jIiwiTUlOQ0ltYWdlSU8iXSxbIk1OQyIsIk1JTkNJbWFnZUlPIl0sWyJtbmMuZ3oiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DLkdaIiwiTUlOQ0ltYWdlSU8iXSxbIm1uYzIiLCJNSU5DSW1hZ2VJTyJdLFsiTU5DMiIsIk1JTkNJbWFnZUlPIl0sWyJtZ2giLCJNR0hJbWFnZUlPIl0sWyJtZ3oiLCJNR0hJbWFnZUlPIl0sWyJtZ2guZ3oiLCJNR0hJbWFnZUlPIl0sWyJtaGEiLCJNZXRhSW1hZ2VJTyJdLFsibWhkIiwiTWV0YUltYWdlSU8iXSxbIm1yYyIsIk1SQ0ltYWdlSU8iXSxbIm5pYSIsIk5pZnRpSW1hZ2VJTyJdLFsibmlpIiwiTmlmdGlJbWFnZUlPIl0sWyJuaWkuZ3oiLCJOaWZ0aUltYWdlSU8iXSxbImhkciIsIk5pZnRpSW1hZ2VJTyJdLFsibnJyZCIsIk5ycmRJbWFnZUlPIl0sWyJOUlJEIiwiTnJyZEltYWdlSU8iXSxbIm5oZHIiLCJOcnJkSW1hZ2VJTyJdLFsiTkhEUiIsIk5ycmRJbWFnZUlPIl0sWyJwbmciLCJQTkdJbWFnZUlPIl0sWyJQTkciLCJQTkdJbWFnZUlPIl0sWyJwaWMiLCJCaW9SYWRJbWFnZUlPIl0sWyJQSUMiLCJCaW9SYWRJbWFnZUlPIl0sWyJ0aWYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGIiwiVElGRkltYWdlSU8iXSxbInRpZmYiLCJUSUZGSW1hZ2VJTyJdLFsiVElGRiIsIlRJRkZJbWFnZUlPIl0sWyJ2dGsiLCJWVEtJbWFnZUlPIl0sWyJWVEsiLCJWVEtJbWFnZUlPIl0sWyJpc3EiLCJTY2FuY29JbWFnZUlPIl0sWyJJU1EiLCJTY2FuY29JbWFnZUlPIl0sWyJmZGYiLCJGREZJbWFnZUlPIl0sWyJGREYiLCJGREZJbWFnZUlPIl1dKSxnZT1wSTtmdW5jdGlvbiBGSShBKXtsZXQgZT1BLnNsaWNlKChBLmxhc3RJbmRleE9mKCIuIiktMT4+PjApKzIpO2lmKGUudG9Mb3dlckNhc2UoKT09PSJneiIpe2xldCB0PUEuc2xpY2UoMCwtMykubGFzdEluZGV4T2YoIi4iKTtlPUEuc2xpY2UoKHQtMT4+PjApKzIpfWVsc2UgaWYoZS50b0xvd2VyQ2FzZSgpPT09ImNib3IiKXtsZXQgdD1BLnNsaWNlKDAsLTUpLmxhc3RJbmRleE9mKCIuIik7ZT1BLnNsaWNlKCh0LTE+Pj4wKSsyKX1lbHNlIGlmKGUudG9Mb3dlckNhc2UoKT09PSJ6c3QiKXtsZXQgdD1BLnNsaWNlKDAsLTEwKS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9ZWxzZSBpZihlLnRvTG93ZXJDYXNlKCk9PT0iemlwIil7bGV0IHQ9QS5zbGljZSgwLC00KS5sYXN0SW5kZXhPZigiLiIpO2U9QS5zbGljZSgodC0xPj4+MCkrMil9cmV0dXJuIGV9dmFyIGtBPUZJO3ZhciBTST1bIlBOR0ltYWdlSU8iLCJNZXRhSW1hZ2VJTyIsIlRJRkZJbWFnZUlPIiwiTmlmdGlJbWFnZUlPIiwiSlBFR0ltYWdlSU8iLCJOcnJkSW1hZ2VJTyIsIlZUS0ltYWdlSU8iLCJCTVBJbWFnZUlPIiwiSERGNUltYWdlSU8iLCJNSU5DSW1hZ2VJTyIsIk1SQ0ltYWdlSU8iLCJMU01JbWFnZUlPIiwiTUdISW1hZ2VJTyIsIkJpb1JhZEltYWdlSU8iLCJHaXBsSW1hZ2VJTyIsIkdFQWR3SW1hZ2VJTyIsIkdFNEltYWdlSU8iLCJHRTVJbWFnZUlPIiwiR0RDTUltYWdlSU8iLCJTY2FuY29JbWFnZUlPIiwiRkRGSW1hZ2VJTyIsIldhc21JbWFnZUlPIiwiV2FzbVpzdGRJbWFnZUlPIl0sTEE9U0k7dmFyIE5JPXtUZXh0RmlsZToiSW50ZXJmYWNlVGV4dEZpbGUiLEJpbmFyeUZpbGU6IkludGVyZmFjZUJpbmFyeUZpbGUiLFRleHRTdHJlYW06IkludGVyZmFjZVRleHRTdHJlYW0iLEJpbmFyeVN0cmVhbToiSW50ZXJmYWNlQmluYXJ5U3RyZWFtIixJbWFnZToiSW50ZXJmYWNlSW1hZ2UiLE1lc2g6IkludGVyZmFjZU1lc2giLFBvbHlEYXRhOiJJbnRlcmZhY2VQb2x5RGF0YSIsSnNvbkNvbXBhdGlibGU6IkludGVyZmFjZUpzb25Db21wYXRpYmxlIn0sdT1OSTt2YXIgUkk9e1RleHQ6IlRleHQiLEJpbmFyeToiQmluYXJ5IixJbWFnZToiSW1hZ2UiLE1lc2g6Ik1lc2gifSxTPVJJO3ZhciBHST17SW50ODoiaW50OCIsVUludDg6InVpbnQ4IixJbnQxNjoiaW50MTYiLFVJbnQxNjoidWludDE2IixJbnQzMjoiaW50MzIiLFVJbnQzMjoidWludDMyIixJbnQ2NDoiaW50NjQiLFVJbnQ2NDoidWludDY0IixTaXplVmFsdWVUeXBlOiJ1aW50NjQiLElkZW50aWZpZXJUeXBlOiJ1aW50NjQiLEluZGV4VmFsdWVUeXBlOiJpbnQ2NCIsT2Zmc2V0VmFsdWVUeXBlOiJpbnQ2NCJ9LEY9R0k7dmFyIFVJPXtGbG9hdDMyOiJmbG9hdDMyIixGbG9hdDY0OiJmbG9hdDY0IixTcGFjZVByZWNpc2lvblR5cGU6ImZsb2F0NjQifSxUPVVJO2Z1bmN0aW9uIGtJKEEsZSl7bGV0IHQ9bnVsbDtzd2l0Y2goQSl7Y2FzZSBGLlVJbnQ4Ont0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ4Ont0PW5ldyBJbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLlVJbnQxNjp7dD1uZXcgVWludDE2QXJyYXkoZSk7YnJlYWt9Y2FzZSBGLkludDE2Ont0PW5ldyBJbnQxNkFycmF5KGUpO2JyZWFrfWNhc2UgRi5VSW50MzI6e3Q9bmV3IFVpbnQzMkFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQzMjp7dD1uZXcgSW50MzJBcnJheShlKTticmVha31jYXNlIEYuVUludDY0Ont0eXBlb2YgZ2xvYmFsVGhpcy5CaWdVaW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdVaW50NjRBcnJheShlKTp0PW5ldyBVaW50OEFycmF5KGUpO2JyZWFrfWNhc2UgRi5JbnQ2NDp7dHlwZW9mIGdsb2JhbFRoaXMuQmlnSW50NjRBcnJheT09ImZ1bmN0aW9uIj90PW5ldyBCaWdJbnQ2NEFycmF5KGUpOnQ9bmV3IFVpbnQ4QXJyYXkoZSk7YnJlYWt9Y2FzZSBULkZsb2F0MzI6e3Q9bmV3IEZsb2F0MzJBcnJheShlKTticmVha31jYXNlIFQuRmxvYXQ2NDp7dD1uZXcgRmxvYXQ2NEFycmF5KGUpO2JyZWFrfWNhc2UibnVsbCI6e3Q9bnVsbDticmVha31jYXNlIG51bGw6e3Q9bnVsbDticmVha31kZWZhdWx0OnRocm93IG5ldyBFcnJvcigiVHlwZSBpcyBub3Qgc3VwcG9ydGVkIGFzIGEgVHlwZWRBcnJheSIpfXJldHVybiB0fXZhciBkPWtJO3ZhciBvdD10eXBlb2YgZ2xvYmFsVGhpcy5TaGFyZWRBcnJheUJ1ZmZlcj09ImZ1bmN0aW9uIixpdD1uZXcgVGV4dEVuY29kZXIsZ3Q9bmV3IFRleHREZWNvZGVyKCJ1dGYtOCIpO2Z1bmN0aW9uIEgoQSxlKXtsZXQgdD17ZmxhZ3M6InIiLGVuY29kaW5nOiJiaW5hcnkifSxJPUEuZnNfb3BlbihlLHQuZmxhZ3MpLGk9QS5mc19zdGF0KGUpLnNpemUsZz1udWxsO290P2c9bmV3IFNoYXJlZEFycmF5QnVmZmVyKGkpOmc9bmV3IEFycmF5QnVmZmVyKGkpO2xldCBuPW5ldyBVaW50OEFycmF5KGcpO3JldHVybiBBLmZzX3JlYWQoSSxuLDAsaSwwKSxBLmZzX2Nsb3NlKEkpLG59ZnVuY3Rpb24gbnQoQSxlLHQpe2xldCBJPW51bGw7b3Q/ST1uZXcgU2hhcmVkQXJyYXlCdWZmZXIodCk6ST1uZXcgQXJyYXlCdWZmZXIodCk7bGV0IHI9bmV3IFVpbnQ4QXJyYXkoSSksaT1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsZSx0KTtyZXR1cm4gci5zZXQoaSkscn1mdW5jdGlvbiB5KEEsZSx0LEkpe2xldCByPTA7cmV0dXJuIGUhPT1udWxsJiYocj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9hcnJheV9hbGxvYyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCx0LEksZS5idWZmZXIuYnl0ZUxlbmd0aF0pLEEuSEVBUFU4LnNldChuZXcgVWludDhBcnJheShlLmJ1ZmZlcikscikpLHJ9ZnVuY3Rpb24gVihBLGUsdCl7bGV0IEk9SlNPTi5zdHJpbmdpZnkoZSkscj1BLmNjYWxsKCJpdGtfd2FzbV9pbnB1dF9qc29uX2FsbG9jIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLHQsSS5sZW5ndGhdKTtBLndyaXRlQXNjaWlUb01lbW9yeShJLHIsITEpfWZ1bmN0aW9uIE4oQSxlLHQsSSl7bGV0IHI9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsZSx0XSksaT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxlLHRdKSxnPW50KEEscixpKTtyZXR1cm4gZChJLGcuYnVmZmVyKX1mdW5jdGlvbiBvZShBLGUpe2xldCB0PUEuY2NhbGwoIml0a193YXNtX291dHB1dF9qc29uX2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIl0sWzAsZV0pLEk9QS5Bc2NpaVRvU3RyaW5nKHQpO3JldHVybiBKU09OLnBhcnNlKEkpfWZ1bmN0aW9uIExJKEEsZSx0LEkpe0khPW51bGwmJkkubGVuZ3RoPjAmJkkuZm9yRWFjaChmdW5jdGlvbihvLEIpe3ZhciBjO3N3aXRjaChvLnR5cGUpe2Nhc2UgdS5UZXh0U3RyZWFtOntsZXQgYT1pdC5lbmNvZGUoby5kYXRhLmRhdGEpLEM9eShBLGEsQiwwKSxRPXtzaXplOmEuYnVmZmVyLmJ5dGVMZW5ndGgsZGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke0N9YH07VihBLFEsQik7YnJlYWt9Y2FzZSB1Lkpzb25Db21wYXRpYmxlOntsZXQgYT1pdC5lbmNvZGUoSlNPTi5zdHJpbmdpZnkoby5kYXRhKSksQz15KEEsYSxCLDApLFE9e3NpemU6YS5idWZmZXIuYnl0ZUxlbmd0aCxkYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gfTtWKEEsUSxCKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgYT1vLmRhdGEuZGF0YSxDPXkoQSxhLEIsMCksUT17c2l6ZTphLmJ1ZmZlci5ieXRlTGVuZ3RoLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWB9O1YoQSxRLEIpO2JyZWFrfWNhc2UgdS5UZXh0RmlsZTp7QS5mc193cml0ZUZpbGUoby5kYXRhLnBhdGgsby5kYXRhLmRhdGEpO2JyZWFrfWNhc2UgdS5CaW5hcnlGaWxlOntBLmZzX3dyaXRlRmlsZShvLmRhdGEucGF0aCxvLmRhdGEuZGF0YSk7YnJlYWt9Y2FzZSB1LkltYWdlOntsZXQgYT1vLmRhdGEsQz15KEEsYS5kYXRhLEIsMCksUT15KEEsYS5kaXJlY3Rpb24sQiwxKSxmPXR5cGVvZigoYz1hLm1ldGFkYXRhKT09PW51bGx8fGM9PT12b2lkIDA/dm9pZCAwOmMuZW50cmllcyk8InUiP0pTT04uc3RyaW5naWZ5KEFycmF5LmZyb20oYS5tZXRhZGF0YS5lbnRyaWVzKCkpKToiW10iLG09e2ltYWdlVHlwZTphLmltYWdlVHlwZSxuYW1lOmEubmFtZSxvcmlnaW46YS5vcmlnaW4sc3BhY2luZzphLnNwYWNpbmcsZGlyZWN0aW9uOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLHNpemU6YS5zaXplLGRhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsbWV0YWRhdGE6Zn07VihBLG0sQik7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBhPW8uZGF0YSxDPXkoQSxhLnBvaW50cyxCLDApLFE9eShBLGEuY2VsbHMsQiwxKSxmPXkoQSxhLnBvaW50RGF0YSxCLDIpLG09eShBLGEuY2VsbERhdGEsQiwzKSx3PXttZXNoVHlwZTphLm1lc2hUeXBlLG5hbWU6YS5uYW1lLG51bWJlck9mUG9pbnRzOmEubnVtYmVyT2ZQb2ludHMscG9pbnRzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Q31gLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGNlbGxCdWZmZXJTaXplOmEuY2VsbEJ1ZmZlclNpemUsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7Zn1gLG51bWJlck9mQ2VsbFBpeGVsczphLm51bWJlck9mQ2VsbFBpeGVscyxjZWxsRGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke219YH07VihBLHcsQik7YnJlYWt9Y2FzZSB1LlBvbHlEYXRhOntsZXQgYT1vLmRhdGEsQz15KEEsYS5wb2ludHMsQiwwKSxRPXkoQSxhLnZlcnRpY2VzLEIsMSksZj15KEEsYS5saW5lcyxCLDIpLG09eShBLGEucG9seWdvbnMsQiwzKSx3PXkoQSxhLnRyaWFuZ2xlU3RyaXBzLEIsNCksTz15KEEsYS5wb2ludERhdGEsQiw1KSxLPXkoQSxhLnBvaW50RGF0YSxCLDYpLEpBPXtwb2x5RGF0YVR5cGU6YS5wb2x5RGF0YVR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtDfWAsdmVydGljZXNCdWZmZXJTaXplOmEudmVydGljZXNCdWZmZXJTaXplLHZlcnRpY2VzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7UX1gLGxpbmVzQnVmZmVyU2l6ZTphLmxpbmVzQnVmZmVyU2l6ZSxsaW5lczpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke2Z9YCxwb2x5Z29uc0J1ZmZlclNpemU6YS5wb2x5Z29uc0J1ZmZlclNpemUscG9seWdvbnM6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHttfWAsdHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplOmEudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplLHRyaWFuZ2xlU3RyaXBzOmBkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsuYWRkcmVzcywwOiR7d31gLG51bWJlck9mUG9pbnRQaXhlbHM6YS5udW1iZXJPZlBvaW50UGl4ZWxzLHBvaW50RGF0YTpgZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLmFkZHJlc3MsMDoke099YCxudW1iZXJPZkNlbGxQaXhlbHM6YS5udW1iZXJPZkNlbGxQaXhlbHMsY2VsbERhdGE6YGRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5hZGRyZXNzLDA6JHtLfWB9O1YoQSxKQSxCKTticmVha31jYXNlIFMuVGV4dDp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkJpbmFyeTp7QS5mc193cml0ZUZpbGUoby5wYXRoLG8uZGF0YSk7YnJlYWt9Y2FzZSBTLkltYWdlOntsZXQgYT1vLmRhdGEsQz17aW1hZ2VUeXBlOmEuaW1hZ2VUeXBlLG5hbWU6YS5uYW1lLG9yaWdpbjphLm9yaWdpbixzcGFjaW5nOmEuc3BhY2luZyxkaXJlY3Rpb246ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvZGlyZWN0aW9uLnJhdyIsc2l6ZTphLnNpemUsZGF0YToiZGF0YTphcHBsaWNhdGlvbi92bmQuaXRrLnBhdGgsZGF0YS9kYXRhLnJhdyJ9O2lmKEEuZnNfbWtkaXJzKGAke28ucGF0aH0vZGF0YWApLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAsSlNPTi5zdHJpbmdpZnkoQykpLGEuZGF0YT09PW51bGwpdGhyb3cgRXJyb3IoImltYWdlLmRhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kYXRhLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5kYXRhLmJ1ZmZlcikpLEEuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9kaXJlY3Rpb24ucmF3YCxuZXcgVWludDhBcnJheShhLmRpcmVjdGlvbi5idWZmZXIpKTticmVha31jYXNlIFMuTWVzaDp7bGV0IGE9by5kYXRhLEM9e21lc2hUeXBlOmEubWVzaFR5cGUsbmFtZTphLm5hbWUsbnVtYmVyT2ZQb2ludHM6YS5udW1iZXJPZlBvaW50cyxwb2ludHM6ImRhdGE6YXBwbGljYXRpb24vdm5kLml0ay5wYXRoLGRhdGEvcG9pbnRzLnJhdyIsbnVtYmVyT2ZQb2ludFBpeGVsczphLm51bWJlck9mUG9pbnRQaXhlbHMscG9pbnREYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL3BvaW50RGF0YS5yYXciLG51bWJlck9mQ2VsbHM6YS5udW1iZXJPZkNlbGxzLGNlbGxzOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxzLnJhdyIsbnVtYmVyT2ZDZWxsUGl4ZWxzOmEubnVtYmVyT2ZDZWxsUGl4ZWxzLGNlbGxEYXRhOiJkYXRhOmFwcGxpY2F0aW9uL3ZuZC5pdGsucGF0aCxkYXRhL2NlbGxEYXRhLnJhdyIsY2VsbEJ1ZmZlclNpemU6YS5jZWxsQnVmZmVyU2l6ZX07aWYoQS5mc19ta2RpcnMoYCR7by5wYXRofS9kYXRhYCksQS5mc193cml0ZUZpbGUoYCR7by5wYXRofS9pbmRleC5qc29uYCxKU09OLnN0cmluZ2lmeShDKSksQy5udW1iZXJPZlBvaW50cz4wKXtpZihhLnBvaW50cz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2gucG9pbnRzIGlzIG51bGwiKTtBLmZzX3dyaXRlRmlsZShgJHtvLnBhdGh9L2RhdGEvcG9pbnRzLnJhd2AsbmV3IFVpbnQ4QXJyYXkoYS5wb2ludHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZlBvaW50UGl4ZWxzPjApe2lmKGEucG9pbnREYXRhPT09bnVsbCl0aHJvdyBFcnJvcigibWVzaC5wb2ludERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCxuZXcgVWludDhBcnJheShhLnBvaW50RGF0YS5idWZmZXIpKX1pZihDLm51bWJlck9mQ2VsbHM+MCl7aWYoYS5jZWxscz09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbHMgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxscy5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbHMuYnVmZmVyKSl9aWYoQy5udW1iZXJPZkNlbGxQaXhlbHM+MCl7aWYoYS5jZWxsRGF0YT09PW51bGwpdGhyb3cgRXJyb3IoIm1lc2guY2VsbERhdGEgaXMgbnVsbCIpO0EuZnNfd3JpdGVGaWxlKGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgLG5ldyBVaW50OEFycmF5KGEuY2VsbERhdGEuYnVmZmVyKSl9YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgaW5wdXQgSW50ZXJmYWNlVHlwZSIpfX0pLEEucmVzZXRNb2R1bGVTdGRvdXQoKSxBLnJlc2V0TW9kdWxlU3RkZXJyKCk7bGV0IHI9QS5zdGFja1NhdmUoKSxpPTA7dHJ5e2k9QS5jYWxsTWFpbihlLnNsaWNlKCkpfWNhdGNoKG8pe3Rocm93IHR5cGVvZiBvPT0ibnVtYmVyIiYmKGNvbnNvbGUubG9nKCJFeGNlcHRpb24gd2hpbGUgcnVubmluZyBwaXBlbGluZToiKSxjb25zb2xlLmxvZygic3Rkb3V0OiIsQS5nZXRNb2R1bGVTdGRvdXQoKSksY29uc29sZS5lcnJvcigic3RkZXJyOiIsQS5nZXRNb2R1bGVTdGRlcnIoKSksdHlwZW9mIEEuZ2V0RXhjZXB0aW9uTWVzc2FnZTwidSI/Y29uc29sZS5lcnJvcigiZXhjZXB0aW9uOiIsQS5nZXRFeGNlcHRpb25NZXNzYWdlKG8pKTpjb25zb2xlLmVycm9yKCJCdWlsZCBtb2R1bGUgaW4gRGVidWcgbW9kZSBmb3IgZXhjZXB0aW9uIG1lc3NhZ2UgaW5mb3JtYXRpb24uIikpLG99ZmluYWxseXtBLnN0YWNrUmVzdG9yZShyKX1sZXQgZz1BLmdldE1vZHVsZVN0ZG91dCgpLG49QS5nZXRNb2R1bGVTdGRlcnIoKSxFPVtdO3JldHVybiB0IT1udWxsJiZ0Lmxlbmd0aD4wJiZpPT09MCYmdC5mb3JFYWNoKGZ1bmN0aW9uKG8sQil7bGV0IGM9bnVsbDtzd2l0Y2goby50eXBlKXtjYXNlIHUuVGV4dFN0cmVhbTp7bGV0IEM9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X2FkZHJlc3MiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksUT1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfc2l6ZSIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxmPW5ldyBVaW50OEFycmF5KEEuSEVBUFU4LmJ1ZmZlcixDLFEpO2M9e2RhdGE6Z3QuZGVjb2RlKGYpfTticmVha31jYXNlIHUuSnNvbkNvbXBhdGlibGU6e2xldCBDPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9hZGRyZXNzIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pLFE9QS5jY2FsbCgiaXRrX3dhc21fb3V0cHV0X2FycmF5X3NpemUiLCJudW1iZXIiLFsibnVtYmVyIiwibnVtYmVyIiwibnVtYmVyIl0sWzAsQiwwXSksZj1uZXcgVWludDhBcnJheShBLkhFQVBVOC5idWZmZXIsQyxRKTtjPUpTT04ucGFyc2UoZ3QuZGVjb2RlKGYpKTticmVha31jYXNlIHUuQmluYXJ5U3RyZWFtOntsZXQgQz1BLmNjYWxsKCJpdGtfd2FzbV9vdXRwdXRfYXJyYXlfYWRkcmVzcyIsIm51bWJlciIsWyJudW1iZXIiLCJudW1iZXIiLCJudW1iZXIiXSxbMCxCLDBdKSxRPUEuY2NhbGwoIml0a193YXNtX291dHB1dF9hcnJheV9zaXplIiwibnVtYmVyIixbIm51bWJlciIsIm51bWJlciIsIm51bWJlciJdLFswLEIsMF0pO2M9e2RhdGE6bnQoQSxDLFEpfTticmVha31jYXNlIHUuVGV4dEZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpBLmZzX3JlYWRGaWxlKG8uZGF0YS5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KX07YnJlYWt9Y2FzZSB1LkJpbmFyeUZpbGU6e2M9e3BhdGg6by5kYXRhLnBhdGgsZGF0YTpIKEEsby5kYXRhLnBhdGgpfTticmVha31jYXNlIHUuSW1hZ2U6e2xldCBDPW9lKEEsQik7Qy5kYXRhPU4oQSxCLDAsQy5pbWFnZVR5cGUuY29tcG9uZW50VHlwZSksQy5kaXJlY3Rpb249TihBLEIsMSxULkZsb2F0NjQpLEMubWV0YWRhdGE9bmV3IE1hcChDLm1ldGFkYXRhKSxjPUM7YnJlYWt9Y2FzZSB1Lk1lc2g6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUpOkMucG9pbnRzPWQoQy5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mQ2VsbHM+MD9DLmNlbGxzPU4oQSxCLDEsQy5tZXNoVHlwZS5jZWxsQ29tcG9uZW50VHlwZSk6Qy5jZWxscz1kKEMubWVzaFR5cGUuY2VsbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiwyLEMubWVzaFR5cGUucG9pbnRQaXhlbENvbXBvbmVudFR5cGUpOkMucG9pbnREYXRhPWQoQy5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLEMubnVtYmVyT2ZDZWxsUGl4ZWxzPjA/Qy5jZWxsRGF0YT1OKEEsQiwzLEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMubWVzaFR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpLGM9QzticmVha31jYXNlIHUuUG9seURhdGE6e2xldCBDPW9lKEEsQik7Qy5udW1iZXJPZlBvaW50cz4wP0MucG9pbnRzPU4oQSxCLDAsVC5GbG9hdDMyKTpDLnBvaW50cz1uZXcgRmxvYXQzMkFycmF5LEMudmVydGljZXNCdWZmZXJTaXplPjA/Qy52ZXJ0aWNlcz1OKEEsQiwxLEYuVUludDMyKTpDLnZlcnRpY2VzPW5ldyBVaW50MzJBcnJheSxDLmxpbmVzQnVmZmVyU2l6ZT4wP0MubGluZXM9TihBLEIsMixGLlVJbnQzMik6Qy5saW5lcz1uZXcgVWludDMyQXJyYXksQy5wb2x5Z29uc0J1ZmZlclNpemU+MD9DLnBvbHlnb25zPU4oQSxCLDMsRi5VSW50MzIpOkMucG9seWdvbnM9bmV3IFVpbnQzMkFycmF5LEMudHJpYW5nbGVTdHJpcHNCdWZmZXJTaXplPjA/Qy50cmlhbmdsZVN0cmlwcz1OKEEsQiw0LEYuVUludDMyKTpDLnRyaWFuZ2xlU3RyaXBzPW5ldyBVaW50MzJBcnJheSxDLm51bWJlck9mUG9pbnRQaXhlbHM+MD9DLnBvaW50RGF0YT1OKEEsQiw1LEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlKTpDLnBvaW50RGF0YT1kKEMucG9seURhdGFUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSksQy5udW1iZXJPZkNlbGxQaXhlbHM+MD9DLmNlbGxEYXRhPU4oQSxCLDYsQy5wb2x5RGF0YVR5cGUuY2VsbFBpeGVsQ29tcG9uZW50VHlwZSk6Qy5jZWxsRGF0YT1kKEMucG9seURhdGFUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKSxjPUM7YnJlYWt9Y2FzZSBTLlRleHQ6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtjPUEuZnNfcmVhZEZpbGUoby5wYXRoLHtlbmNvZGluZzoidXRmOCJ9KTticmVha31jYXNlIFMuQmluYXJ5OntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7Yz1IKEEsby5wYXRoKTticmVha31jYXNlIFMuSW1hZ2U6e2lmKHR5cGVvZiBvLnBhdGg+InUiKXRocm93IG5ldyBFcnJvcigib3V0cHV0LnBhdGggbm90IGRlZmluZWQiKTtsZXQgQz1BLmZzX3JlYWRGaWxlKGAke28ucGF0aH0vaW5kZXguanNvbmAse2VuY29kaW5nOiJ1dGY4In0pLFE9SlNPTi5wYXJzZShDKSxmPUgoQSxgJHtvLnBhdGh9L2RhdGEvZGF0YS5yYXdgKTtRLmRhdGE9ZChRLmltYWdlVHlwZS5jb21wb25lbnRUeXBlLGYuYnVmZmVyKTtsZXQgbT1IKEEsYCR7by5wYXRofS9kYXRhL2RpcmVjdGlvbi5yYXdgKTtRLmRpcmVjdGlvbj1kKFQuRmxvYXQ2NCxtLmJ1ZmZlciksYz1RO2JyZWFrfWNhc2UgUy5NZXNoOntpZih0eXBlb2Ygby5wYXRoPiJ1Iil0aHJvdyBuZXcgRXJyb3IoIm91dHB1dC5wYXRoIG5vdCBkZWZpbmVkIik7bGV0IEM9QS5mc19yZWFkRmlsZShgJHtvLnBhdGh9L2luZGV4Lmpzb25gLHtlbmNvZGluZzoidXRmOCJ9KSxRPUpTT04ucGFyc2UoQyk7aWYoUS5udW1iZXJPZlBvaW50cz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL3BvaW50cy5yYXdgKTtRLnBvaW50cz1kKFEubWVzaFR5cGUucG9pbnRDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnRzPWQoUS5tZXNoVHlwZS5wb2ludENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtpZihRLm51bWJlck9mUG9pbnRQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9wb2ludERhdGEucmF3YCk7US5wb2ludERhdGE9ZChRLm1lc2hUeXBlLnBvaW50UGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEucG9pbnREYXRhPWQoUS5tZXNoVHlwZS5wb2ludFBpeGVsQ29tcG9uZW50VHlwZSxuZXcgQXJyYXlCdWZmZXIoMCkpO2lmKFEubnVtYmVyT2ZDZWxscz4wKXtsZXQgZj1IKEEsYCR7by5wYXRofS9kYXRhL2NlbGxzLnJhd2ApO1EuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbHM9ZChRLm1lc2hUeXBlLmNlbGxDb21wb25lbnRUeXBlLG5ldyBBcnJheUJ1ZmZlcigwKSk7aWYoUS5udW1iZXJPZkNlbGxQaXhlbHM+MCl7bGV0IGY9SChBLGAke28ucGF0aH0vZGF0YS9jZWxsRGF0YS5yYXdgKTtRLmNlbGxEYXRhPWQoUS5tZXNoVHlwZS5jZWxsUGl4ZWxDb21wb25lbnRUeXBlLGYuYnVmZmVyKX1lbHNlIFEuY2VsbERhdGE9ZChRLm1lc2hUeXBlLmNlbGxQaXhlbENvbXBvbmVudFR5cGUsbmV3IEFycmF5QnVmZmVyKDApKTtjPVE7YnJlYWt9ZGVmYXVsdDp0aHJvdyBFcnJvcigiVW5zdXBwb3J0ZWQgb3V0cHV0IEludGVyZmFjZVR5cGUiKX1sZXQgYT17dHlwZTpvLnR5cGUsZGF0YTpjfTtFLnB1c2goYSl9KSx7cmV0dXJuVmFsdWU6aSxzdGRvdXQ6ZyxzdGRlcnI6bixvdXRwdXRzOkV9fXZhciB6PUxJO3ZhciBvQT1mdW5jdGlvbihBKXtyZXR1cm4gdGhpcyBpbnN0YW5jZW9mIG9BPyh0aGlzLnY9QSx0aGlzKTpuZXcgb0EoQSl9LE9JPWZ1bmN0aW9uKEEsZSx0KXtpZighU3ltYm9sLmFzeW5jSXRlcmF0b3IpdGhyb3cgbmV3IFR5cGVFcnJvcigiU3ltYm9sLmFzeW5jSXRlcmF0b3IgaXMgbm90IGRlZmluZWQuIik7dmFyIEk9dC5hcHBseShBLGV8fFtdKSxyLGk9W107cmV0dXJuIHI9e30sZygibmV4dCIpLGcoInRocm93IiksZygicmV0dXJuIikscltTeW1ib2wuYXN5bmNJdGVyYXRvcl09ZnVuY3Rpb24oKXtyZXR1cm4gdGhpc30scjtmdW5jdGlvbiBnKGEpe0lbYV0mJihyW2FdPWZ1bmN0aW9uKEMpe3JldHVybiBuZXcgUHJvbWlzZShmdW5jdGlvbihRLGYpe2kucHVzaChbYSxDLFEsZl0pPjF8fG4oYSxDKX0pfSl9ZnVuY3Rpb24gbihhLEMpe3RyeXtFKElbYV0oQykpfWNhdGNoKFEpe2MoaVswXVszXSxRKX19ZnVuY3Rpb24gRShhKXthLnZhbHVlIGluc3RhbmNlb2Ygb0E/UHJvbWlzZS5yZXNvbHZlKGEudmFsdWUudikudGhlbihvLEIpOmMoaVswXVsyXSxhKX1mdW5jdGlvbiBvKGEpe24oIm5leHQiLGEpfWZ1bmN0aW9uIEIoYSl7bigidGhyb3ciLGEpfWZ1bmN0aW9uIGMoYSxDKXthKEMpLGkuc2hpZnQoKSxpLmxlbmd0aCYmbihpWzBdWzBdLGlbMF1bMV0pfX0sSkk9ZnVuY3Rpb24oQSl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBlPUFbU3ltYm9sLmFzeW5jSXRlcmF0b3JdLHQ7cmV0dXJuIGU/ZS5jYWxsKEEpOihBPXR5cGVvZiBfX3ZhbHVlcz09ImZ1bmN0aW9uIj9fX3ZhbHVlcyhBKTpBW1N5bWJvbC5pdGVyYXRvcl0oKSx0PXt9LEkoIm5leHQiKSxJKCJ0aHJvdyIpLEkoInJldHVybiIpLHRbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHQpO2Z1bmN0aW9uIEkoaSl7dFtpXT1BW2ldJiZmdW5jdGlvbihnKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24obixFKXtnPUFbaV0oZykscihuLEUsZy5kb25lLGcudmFsdWUpfSl9fWZ1bmN0aW9uIHIoaSxnLG4sRSl7UHJvbWlzZS5yZXNvbHZlKEUpLnRoZW4oZnVuY3Rpb24obyl7aSh7dmFsdWU6byxkb25lOm59KX0sZyl9fTtmdW5jdGlvbiBNSShBKXtyZXR1cm4gT0kodGhpcyxhcmd1bWVudHMsZnVuY3Rpb24qKCl7Zm9yKGxldCB0PTA7dDxMQS5sZW5ndGg7dCsrKXtsZXQgST1MQVt0XSsiLXJlYWQtaW1hZ2UiLHI9eWllbGQgb0EoRyhJLEEuY29uZmlnLmltYWdlSU9VcmwpKTt5aWVsZCB5aWVsZCBvQShyKX19KX1hc3luYyBmdW5jdGlvbiBiSShBLGUpe3ZhciB0LEk7aWYoQS5taW1lVHlwZSYmaWUuaGFzKEEubWltZVR5cGUpKXtsZXQgbj1pZS5nZXQoQS5taW1lVHlwZSkrZTtyZXR1cm4gYXdhaXQgRyhuLEEuY29uZmlnLmltYWdlSU9VcmwpfWxldCByPWtBKEEuZmlsZU5hbWUpO2lmKGdlLmhhcyhyKSl7bGV0IG49Z2UuZ2V0KHIpK2U7cmV0dXJuIGF3YWl0IEcobixBLmNvbmZpZy5pbWFnZUlPVXJsKX1mb3IobGV0IG49MDtuPExBLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsSkkoTUkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBuZT1iSTt2YXIgSEk9bmV3IE1hcChbXSksYWU9SEk7dmFyIFlJPW5ldyBNYXAoW1sidnRrIiwiVlRLUG9seURhdGFNZXNoSU8iXSxbIlZUSyIsIlZUS1BvbHlEYXRhTWVzaElPIl0sWyJieXUiLCJCWVVNZXNoSU8iXSxbIkJZVSIsIkJZVU1lc2hJTyJdLFsiZnNhIiwiRnJlZVN1cmZlckFzY2lpTWVzaElPIl0sWyJGU0EiLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iXSxbImZzYiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIkZTQiIsIkZyZWVTdXJmZXJCaW5hcnlNZXNoSU8iXSxbIm9iaiIsIk9CSk1lc2hJTyJdLFsiT0JKIiwiT0JKTWVzaElPIl0sWyJvZmYiLCJPRkZNZXNoSU8iXSxbIk9GRiIsIk9GRk1lc2hJTyJdLFsic3RsIiwiU1RMTWVzaElPIl0sWyJTVEwiLCJTVExNZXNoSU8iXSxbInN3YyIsIlNXQ01lc2hJTyJdLFsiU1dDIiwiU1dDTWVzaElPIl0sWyJpd20iLCJXYXNtTWVzaElPIl0sWyJpd20uY2JvciIsIldhc21NZXNoSU8iXSxbIml3bS5jYm9yLnpzdCIsIldhc21ac3RkTWVzaElPIl1dKSxzZT1ZSTt2YXIgcUk9WyJCWVVNZXNoSU8iLCJGcmVlU3VyZmVyQXNjaWlNZXNoSU8iLCJGcmVlU3VyZmVyQmluYXJ5TWVzaElPIiwiT0JKTWVzaElPIiwiT0ZGTWVzaElPIiwiU1RMTWVzaElPIiwiU1dDTWVzaElPIiwiVlRLUG9seURhdGFNZXNoSU8iLCJXYXNtTWVzaElPIiwiV2FzbVpzdGRNZXNoSU8iXSxPQT1xSTt2YXIgbkE9ZnVuY3Rpb24oQSl7cmV0dXJuIHRoaXMgaW5zdGFuY2VvZiBuQT8odGhpcy52PUEsdGhpcyk6bmV3IG5BKEEpfSxUST1mdW5jdGlvbihBLGUsdCl7aWYoIVN5bWJvbC5hc3luY0l0ZXJhdG9yKXRocm93IG5ldyBUeXBlRXJyb3IoIlN5bWJvbC5hc3luY0l0ZXJhdG9yIGlzIG5vdCBkZWZpbmVkLiIpO3ZhciBJPXQuYXBwbHkoQSxlfHxbXSkscixpPVtdO3JldHVybiByPXt9LGcoIm5leHQiKSxnKCJ0aHJvdyIpLGcoInJldHVybiIpLHJbU3ltYm9sLmFzeW5jSXRlcmF0b3JdPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXN9LHI7ZnVuY3Rpb24gZyhhKXtJW2FdJiYoclthXT1mdW5jdGlvbihDKXtyZXR1cm4gbmV3IFByb21pc2UoZnVuY3Rpb24oUSxmKXtpLnB1c2goW2EsQyxRLGZdKT4xfHxuKGEsQyl9KX0pfWZ1bmN0aW9uIG4oYSxDKXt0cnl7RShJW2FdKEMpKX1jYXRjaChRKXtjKGlbMF1bM10sUSl9fWZ1bmN0aW9uIEUoYSl7YS52YWx1ZSBpbnN0YW5jZW9mIG5BP1Byb21pc2UucmVzb2x2ZShhLnZhbHVlLnYpLnRoZW4obyxCKTpjKGlbMF1bMl0sYSl9ZnVuY3Rpb24gbyhhKXtuKCJuZXh0IixhKX1mdW5jdGlvbiBCKGEpe24oInRocm93IixhKX1mdW5jdGlvbiBjKGEsQyl7YShDKSxpLnNoaWZ0KCksaS5sZW5ndGgmJm4oaVswXVswXSxpWzBdWzFdKX19LEtJPWZ1bmN0aW9uKEEpe2lmKCFTeW1ib2wuYXN5bmNJdGVyYXRvcil0aHJvdyBuZXcgVHlwZUVycm9yKCJTeW1ib2wuYXN5bmNJdGVyYXRvciBpcyBub3QgZGVmaW5lZC4iKTt2YXIgZT1BW1N5bWJvbC5hc3luY0l0ZXJhdG9yXSx0O3JldHVybiBlP2UuY2FsbChBKTooQT10eXBlb2YgX192YWx1ZXM9PSJmdW5jdGlvbiI/X192YWx1ZXMoQSk6QVtTeW1ib2wuaXRlcmF0b3JdKCksdD17fSxJKCJuZXh0IiksSSgidGhyb3ciKSxJKCJyZXR1cm4iKSx0W1N5bWJvbC5hc3luY0l0ZXJhdG9yXT1mdW5jdGlvbigpe3JldHVybiB0aGlzfSx0KTtmdW5jdGlvbiBJKGkpe3RbaV09QVtpXSYmZnVuY3Rpb24oZyl7cmV0dXJuIG5ldyBQcm9taXNlKGZ1bmN0aW9uKG4sRSl7Zz1BW2ldKGcpLHIobixFLGcuZG9uZSxnLnZhbHVlKX0pfX1mdW5jdGlvbiByKGksZyxuLEUpe1Byb21pc2UucmVzb2x2ZShFKS50aGVuKGZ1bmN0aW9uKG8pe2koe3ZhbHVlOm8sZG9uZTpufSl9LGcpfX07ZnVuY3Rpb24geEkoQSl7cmV0dXJuIFRJKHRoaXMsYXJndW1lbnRzLGZ1bmN0aW9uKigpe2ZvcihsZXQgdD0wO3Q8T0EubGVuZ3RoO3QrKyl7bGV0IEk9T0FbdF0rIi1yZWFkLW1lc2giLHI9eWllbGQgbkEoRyhJLEEuY29uZmlnLm1lc2hJT1VybCkpO3lpZWxkIHlpZWxkIG5BKHIpfX0pfWFzeW5jIGZ1bmN0aW9uIFBJKEEsZSl7dmFyIHQsSTtpZihBLm1pbWVUeXBlJiZhZS5oYXMoQS5taW1lVHlwZSkpe2xldCBuPWFlLmdldChBLm1pbWVUeXBlKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1sZXQgcj1rQShBLmZpbGVOYW1lKTtpZihzZS5oYXMocikpe2xldCBuPXNlLmdldChyKStlO3JldHVybiBhd2FpdCBHKG4sQS5jb25maWcubWVzaElPVXJsKX1mb3IobGV0IG49MDtuPE9BLmxlbmd0aDsrK24pe2xldCBFPTA7dHJ5e2Zvcih2YXIgaT0odD12b2lkIDAsS0koeEkoQSkpKSxnO2c9YXdhaXQgaS5uZXh0KCksIWcuZG9uZTspe2xldCBvPWcudmFsdWU7dHJ5e2xldHtyZXR1cm5WYWx1ZTpCLG91dHB1dHM6Y309YXdhaXQgeihvLEEuYXJncyxBLm91dHB1dHMsQS5pbnB1dHMpO2lmKEI9PT0wKXJldHVybiBvfWNhdGNoe31FKyt9fWNhdGNoKG8pe3Q9e2Vycm9yOm99fWZpbmFsbHl7dHJ5e2cmJiFnLmRvbmUmJihJPWkucmV0dXJuKSYmYXdhaXQgSS5jYWxsKGkpfWZpbmFsbHl7aWYodCl0aHJvdyB0LmVycm9yfX19dGhyb3cgRXJyb3IoYENvdWxkIG5vdCBmaW5kIElPIGZvcjogJHtBLmZpbGVOYW1lfWApfXZhciBDZT1QSTt2YXIgV0k9dHlwZW9mIGdsb2JhbFRoaXMuU2hhcmVkQXJyYXlCdWZmZXI8InUiO2Z1bmN0aW9uIGpJKEEpe2lmKEE9PW51bGwpcmV0dXJuW107bGV0IGU9W107Zm9yKGxldCB0PTA7dDxBLmxlbmd0aDt0Kyspe2xldCBJPVpJKEFbdF0pO0khPT1udWxsJiZlLnB1c2goSSl9cmV0dXJuIGV9ZnVuY3Rpb24gWkkoQSl7aWYoQT09bnVsbClyZXR1cm4gbnVsbDtsZXQgZT1udWxsO3JldHVybiBBLmJ1ZmZlciE9PXZvaWQgMD9lPUEuYnVmZmVyOkEuYnl0ZUxlbmd0aCE9PXZvaWQgMCYmKGU9QSksV0kmJmUgaW5zdGFuY2VvZiBTaGFyZWRBcnJheUJ1ZmZlcj9udWxsOmV9dmFyIGF0PWpJO2Z1bmN0aW9uIF9JKEEpe3JldHVybltBLmRhdGEsQS5kaXJlY3Rpb25dfXZhciBCZT1fSTtmdW5jdGlvbiBWSShBKXtyZXR1cm5bQS5wb2ludHMsQS5wb2ludERhdGEsQS5jZWxscyxBLmNlbGxEYXRhXX12YXIgUWU9Vkk7ZnVuY3Rpb24gekkoQSl7cmV0dXJuW0EucG9pbnRzLEEudmVydGljZXMsQS5saW5lcyxBLnBvbHlnb25zLEEudHJpYW5nbGVTdHJpcHMsQS5wb2ludERhdGEsQS5jZWxsRGF0YV19dmFyIHN0PXpJO2FzeW5jIGZ1bmN0aW9uIFhJKEEsZSx0LEkpe2xldCByPXooQSxlLHQsSSksaT1bXTtyZXR1cm4gci5vdXRwdXRzJiZyLm91dHB1dHMuZm9yRWFjaChmdW5jdGlvbihnKXtpZihnLnR5cGU9PT11LkJpbmFyeVN0cmVhbXx8Zy50eXBlPT09dS5CaW5hcnlGaWxlKXtsZXQgbj1nLmRhdGE7aS5wdXNoKG4pfWVsc2UgaWYoZy50eXBlPT09dS5JbWFnZSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5CZShuKSl9ZWxzZSBpZihnLnR5cGU9PT11Lk1lc2gpe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uUWUobikpfWVsc2UgaWYoZy50eXBlPT09dS5Qb2x5RGF0YSl7bGV0IG49Zy5kYXRhO2kucHVzaCguLi5zdChuKSl9ZWxzZSBpZihnLnR5cGU9PT1TLkJpbmFyeSl7bGV0IG49Zy5kYXRhO2kucHVzaChuKX1lbHNlIGlmKGcudHlwZT09PVMuSW1hZ2Upe2xldCBuPWcuZGF0YTtpLnB1c2goLi4uQmUobikpfWVsc2UgaWYoZy50eXBlPT09Uy5NZXNoKXtsZXQgbj1nLmRhdGE7aS5wdXNoKC4uLlFlKG4pKX19KSxIQShyLGF0KGkpKX12YXIgWT1YSTt2YXIgdkk9e21lc2hUb1BvbHlEYXRhOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkpe2xldCByPWF3YWl0IEcoIm1lc2gtdG8tcG9seWRhdGEiLEEubWVzaElPVXJsKTtyZXR1cm4gWShyLGUsdCxJKX0scG9seURhdGFUb01lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSl7bGV0IHI9YXdhaXQgRygicG9seWRhdGEtdG8tbWVzaCIsQS5tZXNoSU9VcmwpO3JldHVybiBZKHIsZSx0LEkpfSxyZWFkSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi1yZWFkLWltYWdlIik7cmV0dXJuIFkoZyxJLHIsaSl9LHdyaXRlSW1hZ2U6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IG5lKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1pbWFnZSIpO3JldHVybiBZKGcsSSxyLGkpfSxyZWFkTWVzaDphc3luYyBmdW5jdGlvbihBLGUsdCxJLHIsaSl7bGV0IGc9YXdhaXQgQ2Uoe2ZpbGVOYW1lOnQsbWltZVR5cGU6ZSxjb25maWc6QSxhcmdzOkksb3V0cHV0czpyLGlucHV0czppfSwiLXJlYWQtbWVzaCIpO3JldHVybiBZKGcsSSxyLGkpfSx3cml0ZU1lc2g6YXN5bmMgZnVuY3Rpb24oQSxlLHQsSSxyLGkpe2xldCBnPWF3YWl0IENlKHtmaWxlTmFtZTp0LG1pbWVUeXBlOmUsY29uZmlnOkEsYXJnczpJLG91dHB1dHM6cixpbnB1dHM6aX0sIi13cml0ZS1tZXNoIik7cmV0dXJuIFkoZyxJLHIsaSl9LHJ1blBpcGVsaW5lOmFzeW5jIGZ1bmN0aW9uKEEsZSx0LEkscixpKXtsZXQgZz10eXBlb2YgQVt0XT4idSI/dDpBW3RdLG49YXdhaXQgRyhlLGcpO3JldHVybiBZKG4sSSxyLGkpfX07RUEodkkpOyUwQS8qISBCdW5kbGVkIGxpY2Vuc2UgaW5mb3JtYXRpb246JTBBJTBBY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczolMEEgICgqKiUwQSAgICogQGxpY2Vuc2UlMEEgICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMlMEEgICAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBBcGFjaGUtMi4wJTBBICAgKiklMEEqLyUwQSc7cHIodXIpO2V4cG9ydHtIQSBhcyBiaW9SYWRSZWFkSW1hZ2UsWUEgYXMgYmlvUmFkV3JpdGVJbWFnZSxPQSBhcyBibXBSZWFkSW1hZ2UsVUEgYXMgYm1wV3JpdGVJbWFnZSx0dCBhcyBmZGZSZWFkSW1hZ2UsZW8gYXMgZmRmV3JpdGVJbWFnZSxYQSBhcyBnZGNtUmVhZEltYWdlLCRBIGFzIGdkY21Xcml0ZUltYWdlLF9BIGFzIGdlNFJlYWRJbWFnZSx6QSBhcyBnZTRXcml0ZUltYWdlLFZBIGFzIGdlNVJlYWRJbWFnZSxaQSBhcyBnZTVXcml0ZUltYWdlLEtBIGFzIGdlQWR3UmVhZEltYWdlLGpBIGFzIGdlQWR3V3JpdGVJbWFnZSx5IGFzIGdldFBpcGVsaW5lV29ya2VyVXJsLEMgYXMgZ2V0UGlwZWxpbmVzQmFzZVVybCxxQSBhcyBnaXBsUmVhZEltYWdlLHZBIGFzIGdpcGxXcml0ZUltYWdlLFNBIGFzIGhkZjVSZWFkSW1hZ2UsV0EgYXMgaGRmNVdyaXRlSW1hZ2Usd0EgYXMganBlZ1JlYWRJbWFnZSxSQSBhcyBqcGVnV3JpdGVJbWFnZSxUQSBhcyBsc21SZWFkSW1hZ2UsSkEgYXMgbHNtV3JpdGVJbWFnZSxCQSBhcyBtZXRhUmVhZEltYWdlLENBIGFzIG1ldGFXcml0ZUltYWdlLExBIGFzIG1naFJlYWRJbWFnZSxNQSBhcyBtZ2hXcml0ZUltYWdlLE5BIGFzIG1pbmNSZWFkSW1hZ2UsUEEgYXMgbWluY1dyaXRlSW1hZ2UseEEgYXMgbXJjUmVhZEltYWdlLEdBIGFzIG1yY1dyaXRlSW1hZ2UsUUEgYXMgbmlmdGlSZWFkSW1hZ2UsaEEgYXMgbmlmdGlXcml0ZUltYWdlLGJBIGFzIG5ycmRSZWFkSW1hZ2Usa0EgYXMgbnJyZFdyaXRlSW1hZ2UsY0EgYXMgcG5nUmVhZEltYWdlLGRBIGFzIHBuZ1dyaXRlSW1hZ2UsbnQgYXMgcmVhZEltYWdlLFZhIGFzIHJlYWRJbWFnZUZpbGVTZXJpZXMsZXQgYXMgc2NhbmNvUmVhZEltYWdlLEF0IGFzIHNjYW5jb1dyaXRlSW1hZ2UscHIgYXMgc2V0UGlwZWxpbmVXb3JrZXJVcmwscGwgYXMgc2V0UGlwZWxpbmVzQmFzZVVybCx5QSBhcyB0aWZmUmVhZEltYWdlLEVBIGFzIHRpZmZXcml0ZUltYWdlLERBIGFzIHZ0a1JlYWRJbWFnZSxGQSBhcyB2dGtXcml0ZUltYWdlLHJ0IGFzIHdhc21SZWFkSW1hZ2UsaXQgYXMgd2FzbVdyaXRlSW1hZ2UsYXQgYXMgd2FzbVpzdGRSZWFkSW1hZ2Usb3QgYXMgd2FzbVpzdGRXcml0ZUltYWdlLFhhIGFzIHdyaXRlSW1hZ2V9OwovKiEgQnVuZGxlZCBsaWNlbnNlIGluZm9ybWF0aW9uOgoKY29tbGluay9kaXN0L2VzbS9jb21saW5rLm1qczoKICAoKioKICAgKiBAbGljZW5zZQogICAqIENvcHlyaWdodCAyMDE5IEdvb2dsZSBMTEMKICAgKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogQXBhY2hlLTIuMAogICAqKQoqLwo=""" default_config = JsPackageConfig(default_js_module) js_package = JsPackage(default_config) diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml b/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml index d9ecee899..f3c44d283 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml +++ b/packages/image-io/python/itkwasm-image-io-emscripten/pyproject.toml @@ -42,6 +42,7 @@ path = "itkwasm_image_io_emscripten/_version.py" dependencies = [ "pytest", "pytest-pyodide", + "itkwasm-image-io-emscripten", ] [project.urls] diff --git a/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py b/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py index d6c91f8b2..b54af232e 100644 --- a/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py +++ b/packages/image-io/python/itkwasm-image-io-emscripten/test/fixtures.py @@ -24,6 +24,5 @@ def input_data(): data = {} for f in test_files: with open(input_base_path / f, 'rb') as fp: - print(str(f.name)) data[str(f.name)] = fp.read() return data \ No newline at end of file diff --git a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py index 6a9beea82..3d187266f 100644 --- a/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py +++ b/packages/image-io/python/itkwasm-image-io-wasi/itkwasm_image_io_wasi/_version.py @@ -1 +1 @@ -__version__ = "0.4.0" +__version__ = "0.5.0" diff --git a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py index 6a9beea82..3d187266f 100644 --- a/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py +++ b/packages/image-io/python/itkwasm-image-io/itkwasm_image_io/_version.py @@ -1 +1 @@ -__version__ = "0.4.0" +__version__ = "0.5.0" diff --git a/packages/image-io/typescript/package.json b/packages/image-io/typescript/package.json index c5aacc7f7..c2db2a557 100644 --- a/packages/image-io/typescript/package.json +++ b/packages/image-io/typescript/package.json @@ -1,6 +1,6 @@ { "name": "@itk-wasm/image-io", - "version": "0.4.0", + "version": "0.5.0", "description": "Input and output for scientific and medical image file formats.", "type": "module", "module": "./dist/index.js", From 723a13a087492d7b6fd098ab1a59e7e8c96520c6 Mon Sep 17 00:00:00 2001 From: Matt McCormick Date: Wed, 8 Nov 2023 23:27:53 -0500 Subject: [PATCH 23/23] build(bindgen): only warn when esm module is not present for python-emscripten --- src/bindgen/python/emscripten/emscripten-package.js | 11 ++++++++++- .../python/emscripten/emscripten-pyodide-module.js | 11 +---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/bindgen/python/emscripten/emscripten-package.js b/src/bindgen/python/emscripten/emscripten-package.js index 4b2b04c63..925fed383 100644 --- a/src/bindgen/python/emscripten/emscripten-package.js +++ b/src/bindgen/python/emscripten/emscripten-package.js @@ -1,3 +1,4 @@ +import fs from 'fs-extra' import path from 'path' import mkdirP from '../../mkdir-p.js' @@ -13,6 +14,14 @@ import emscriptenFunctionModule from './emscripten-function-module.js' import wasmBinaryInterfaceJson from '../../wasm-binary-interface-json.js' function emscriptenPackage(outputDir, buildDir, wasmBinaries, options) { + const defaultJsModulePath = path.join(outputDir, '..', 'typescript', 'dist', 'bundle', 'index-worker-embedded.min.js') + const moduleUrl = options.jsModulePath ?? defaultJsModulePath + if (!fs.existsSync(moduleUrl)) { + console.warn(`Could not find ${moduleUrl}: skipping python emscripten package`) + return + } + const jsModuleContent = btoa(fs.readFileSync(moduleUrl, { encoding: 'utf8', flag: 'r' })) + const packageName = `${options.packageName}-emscripten` const packageDir = path.join(outputDir, packageName) const packageDescription = `${options.packageDescription} Emscripten implementation.` @@ -28,7 +37,7 @@ function emscriptenPackage(outputDir, buildDir, wasmBinaries, options) { const async = true const sync = false packageDunderInit(outputDir, buildDir, wasmBinaries, packageName, packageDescription, packageDir, pypackage, async, sync) - emscriptenPyodideModule(outputDir, packageDir, pypackage, options) + emscriptenPyodideModule(jsModuleContent, packageDir, pypackage) emscriptenTestModule(packageDir, pypackage) const wasmModulesDir = path.join(packageDir, pypackage, 'wasm_modules') diff --git a/src/bindgen/python/emscripten/emscripten-pyodide-module.js b/src/bindgen/python/emscripten/emscripten-pyodide-module.js index 20f9f5182..46067f840 100644 --- a/src/bindgen/python/emscripten/emscripten-pyodide-module.js +++ b/src/bindgen/python/emscripten/emscripten-pyodide-module.js @@ -1,17 +1,8 @@ -import fs from 'fs-extra' import path from 'path' import writeIfOverrideNotPresent from '../../write-if-override-not-present.js' -function emscriptenPyodideModule(outputDir, packageDir, pypackage, options) { - const defaultJsModulePath = path.join(outputDir, '..', 'typescript', 'dist', 'bundle', 'index-worker-embedded.min.js') - const moduleUrl = options.jsModulePath ?? defaultJsModulePath - if (!fs.existsSync(moduleUrl)) { - console.error(`Could not find ${moduleUrl}`) - process.exit(1) - } - const jsModuleContent = btoa(fs.readFileSync(moduleUrl, { encoding: 'utf8', flag: 'r' })) - +function emscriptenPyodideModule(jsModuleContent, packageDir, pypackage) { const moduleContent = `from itkwasm.pyodide import JsPackageConfig, JsPackage from ._version import __version__