diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..48ac639 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,27 @@ +name: GitHub Pages + +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + + - name: Setup Node + uses: actions/setup-node@v2.1.2 + + - name: Build + run: | + cd website + yarn + yarn build + + - name: deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.TOKEN }} + publish_dir: ./website/build diff --git a/.github/workflows/push.yaml b/.github/workflows/push.yaml new file mode 100644 index 0000000..fcf7382 --- /dev/null +++ b/.github/workflows/push.yaml @@ -0,0 +1,28 @@ +name: Push to Master Repo + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + with: + ref: 'master' + - name: Install SSH key + uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.SSH_KEY }} + known_hosts: ${{ secrets.KNOWN_HOSTS }} + - run: | + git remote add official git@github.com:KentoNishi/JTR-CVPR-2024.git + git config --global user.email ${{ secrets.EMAIL }} + git config --global user.name ${{ secrets.USERNAME }} + git checkout master + # squash all commits into one + git reset $(git commit-tree HEAD^{tree} -m "Update at $(date +'%Y-%m-%d %H:%M:%S')") + git push -u official master -f diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3d66e44 --- /dev/null +++ b/.gitignore @@ -0,0 +1,162 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +# lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +ignore diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3becc19 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Kento Nishi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..35a1c13 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# JTR-CVPR-2024 + + + + + + +## Updates +* **May 2024:** Code released for NYUv2 `onelabel` and `randomlabels`. +* **May 2024:** Website updated with the CVPR poster and video. +* **April 2024:** Paper website published at [kentonishi.com/JTR-CVPR-2024](https://kentonishi.com/JTR-CVPR-2024). + + +## Training +```bash +# NYUv2 onelabel +python train_nyuv2.py \ + --data-dir [/some/data/dir] \ + --out-dir [/some/output/dir/nyuv2_onelabel] \ + --ssl-type onelabel \ + --label-dir ./data/nyuv2_settings \ + --seg-baseline 25.75 --depth-baseline 0.6511 --norm-baseline 33.73 + +# NYUv2 randomlabels +python train_nyuv2.py \ + --data-dir [/some/data/dir] \ + --out-dir [/some/output/dir/nyuv2_randomlabels] \ + --ssl-type randomlabels \ + --label-dir ./data/nyuv2_settings \ + --seg-baseline 27.05 --depth-baseline 0.6626 --norm-baseline 33.58 +``` diff --git a/code/data/nyuv2_settings/onelabel.pth b/code/data/nyuv2_settings/onelabel.pth new file mode 100644 index 0000000..c629fdf Binary files /dev/null and b/code/data/nyuv2_settings/onelabel.pth differ diff --git a/code/data/nyuv2_settings/randomlabels.pth b/code/data/nyuv2_settings/randomlabels.pth new file mode 100644 index 0000000..9bf574d Binary files /dev/null and b/code/data/nyuv2_settings/randomlabels.pth differ diff --git a/code/data/pascal-context b/code/data/pascal-context new file mode 120000 index 0000000..352e40d --- /dev/null +++ b/code/data/pascal-context @@ -0,0 +1 @@ +/n/home11/jskim/vcg_natural/multi-task/pascal-context \ No newline at end of file diff --git a/code/datasets/nyuv2.py b/code/datasets/nyuv2.py new file mode 100644 index 0000000..142e065 --- /dev/null +++ b/code/datasets/nyuv2.py @@ -0,0 +1,148 @@ +from torch.utils.data.dataset import Dataset + +import os +import torch +import fnmatch +import numpy as np +import random +import torch.nn.functional as F +from .randaugment import ImgAugment + + +class RandomScaleCrop(object): + """ + Credit to Jialong Wu from https://github.com/lorenmt/mtan/issues/34. + """ + + def __init__(self, scale=[1.0, 1.2, 1.5]): + self.scale = scale + + def __call__(self, img, label, depth, normal): + height, width = img.shape[-2:] + sc = self.scale[random.randint(0, len(self.scale) - 1)] + h, w = int(height / sc), int(width / sc) + i = random.randint(0, height - h) + j = random.randint(0, width - w) + # pdb.set_trace() + img_ = F.interpolate( + img[None, :, i : i + h, j : j + w], + size=(height, width), + mode="bilinear", + align_corners=True, + ).squeeze(0) + label_ = ( + F.interpolate( + label[None, None, i : i + h, j : j + w], + size=(height, width), + mode="nearest", + ) + .squeeze(0) + .squeeze(0) + ) + depth_ = F.interpolate( + depth[None, :, i : i + h, j : j + w], size=(height, width), mode="nearest" + ).squeeze(0) + normal_ = F.interpolate( + normal[None, :, i : i + h, j : j + w], + size=(height, width), + mode="bilinear", + align_corners=True, + ).squeeze(0) + _sc = sc + _h, _w, _i, _j = h, w, i, j + + return ( + img_, + label_, + depth_ / sc, + normal_, + torch.tensor([_sc, _h, _w, _i, _j, height, width]), + ) + + +class NYUv2_MTL(Dataset): + """ + This file is directly modified from https://pytorch.org/docs/stable/torchvision/datasets.html + """ + + def __init__( + self, + root, + train=True, + ): + self.train = train + self.root = os.path.expanduser(root) + self.augmenter = ImgAugment( + num_ops=2, magnitude=6, num_magnitude_bins=31, magnitude_sampling=True + ) + + # R\read the data file + if train: + self.data_path = root + "/train" + else: + self.data_path = root + "/val" + + # calculate data length + self.data_len = len( + fnmatch.filter(os.listdir(self.data_path + "/image"), "*.npy") + ) + + def __getitem__(self, index): + # get image name from the pandas df + image = torch.from_numpy( + np.moveaxis( + np.load(self.data_path + "/image/{:d}.npy".format(index)), -1, 0 + ) + ) + semantic = torch.from_numpy( + np.load(self.data_path + "/label/{:d}.npy".format(index)) + ) + depth = torch.from_numpy( + np.moveaxis( + np.load(self.data_path + "/depth/{:d}.npy".format(index)), -1, 0 + ) + ) + normal = torch.from_numpy( + np.moveaxis( + np.load(self.data_path + "/normal/{:d}.npy".format(index)), -1, 0 + ) + ) + + if self.train: + image_0, semantic_0, depth_0, normal_0, _ = RandomScaleCrop()( + image, semantic, depth, normal + ) + image_1, semantic_1, depth_1, normal_1, _ = RandomScaleCrop()( + image_0, semantic_0, depth_0, normal_0 + ) + image_2, semantic_2, depth_2, normal_2, _ = RandomScaleCrop()( + image_0, semantic_0, depth_0, normal_0 + ) + image_0 = self.augmenter(image_0) + image_1 = self.augmenter(image_1) + image_2 = self.augmenter(image_2) + return ( + index, + image_0.type(torch.FloatTensor), + semantic_0.type(torch.FloatTensor), + depth_0.type(torch.FloatTensor), + normal_0.type(torch.FloatTensor), + image_1.type(torch.FloatTensor), + semantic_1.type(torch.FloatTensor), + depth_1.type(torch.FloatTensor), + normal_1.type(torch.FloatTensor), + image_2.type(torch.FloatTensor), + semantic_2.type(torch.FloatTensor), + depth_2.type(torch.FloatTensor), + normal_2.type(torch.FloatTensor), + ) + else: + return ( + image.type(torch.FloatTensor), + semantic.type(torch.FloatTensor), + depth.type(torch.FloatTensor), + normal.type(torch.FloatTensor), + ) + + def __len__(self): + return self.data_len diff --git a/code/datasets/randaugment.py b/code/datasets/randaugment.py new file mode 100644 index 0000000..ab54793 --- /dev/null +++ b/code/datasets/randaugment.py @@ -0,0 +1,194 @@ +###### +# Augmentation on pytorch tensor +###### +import torch +from torch import Tensor +import math +import torchvision.transforms as T +from torchvision.transforms import functional as F, InterpolationMode +from typing import Dict, List, Optional, Tuple + + +class ImgAugment(torch.nn.Module): + """ + Reference: RandAugment + https://pytorch.org/vision/main/_modules/torchvision/transforms/autoaugment.html#RandAugment + """ + + def __init__( + self, + num_ops: int = 2, + magnitude: int = 6, # default 9, range from 0 ~ num_magnitude_bins + num_magnitude_bins: int = 31, # magnitude resolution + interpolation: InterpolationMode = InterpolationMode.NEAREST, + fill: Optional[List[float]] = None, + magnitude_sampling=True, + ) -> None: + super().__init__() + self.num_ops = num_ops + self.magnitude = magnitude + self.num_magnitude_bins = num_magnitude_bins + self.interpolation = interpolation + self.fill = fill + self.magnitude_sampling = magnitude_sampling + + def _augmentation_space( + self, num_bins: int, image_size: Tuple[int, int] + ) -> Dict[str, Tuple[Tensor, bool]]: + return { + # op_name: (magnitudes, signed) + "Identity": (torch.tensor(0.0), False), + # "ShearX": (torch.linspace(0.0, 0.3, num_bins), True), + # "ShearY": (torch.linspace(0.0, 0.3, num_bins), True), + # "TranslateX": (torch.linspace(0.0, 150.0 / 331.0 * image_size[1], num_bins), True), + # "TranslateY": (torch.linspace(0.0, 150.0 / 331.0 * image_size[0], num_bins), True), + # "Rotate": (torch.linspace(0.0, 30.0, num_bins), True), + "Brightness": (torch.linspace(0.0, 0.9, num_bins), True), + "Color": (torch.linspace(0.0, 0.9, num_bins), True), + "Contrast": (torch.linspace(0.0, 0.9, num_bins), True), + "Sharpness": (torch.linspace(0.0, 0.9, num_bins), True), + "Posterize": ( + 8 - (torch.arange(num_bins) / ((num_bins - 1) / 4)).round().int(), + False, + ), + "Solarize": (torch.linspace(255.0, 0.0, num_bins), False), + "AutoContrast": (torch.tensor(0.0), False), + "Equalize": (torch.tensor(0.0), False), + } + + def forward(self, img: Tensor) -> Tensor: + """ + img (PIL Image or Tensor): Image to be transformed. + + Returns: + PIL Image or Tensor: Transformed image. + """ + fill = self.fill + # channels, height, width = F.get_dimensions(img) + channels, height, width = img.shape + if isinstance(img, Tensor): + if isinstance(fill, (int, float)): + fill = [float(fill)] * channels + elif fill is not None: + fill = [float(f) for f in fill] + + op_meta = self._augmentation_space(self.num_magnitude_bins, (height, width)) + for _ in range(self.num_ops): + op_index = int(torch.randint(len(op_meta), (1,)).item()) + op_name = list(op_meta.keys())[op_index] + magnitudes, signed = op_meta[op_name] + if self.magnitude_sampling: + sampled_magnitude = torch.randint(self.magnitude, (1,)).item() + else: + sampled_magnitude = self.magnitude + magnitude = ( + float(magnitudes[sampled_magnitude].item()) + if magnitudes.ndim > 0 + else 0.0 + ) + if signed and torch.randint(2, (1,)): + magnitude *= -1.0 + img = _apply_op( + img, op_name, magnitude, interpolation=self.interpolation, fill=fill + ) + + return img + + +def _apply_op( + img: Tensor, + op_name: str, + magnitude: float, + interpolation: InterpolationMode, + fill: Optional[List[float]], +): + if op_name == "ShearX": + # magnitude should be arctan(magnitude) + # official autoaug: (1, level, 0, 0, 1, 0) + # https://github.com/tensorflow/models/blob/dd02069717128186b88afa8d857ce57d17957f03/research/autoaugment/augmentation_transforms.py#L290 + # compared to + # torchvision: (1, tan(level), 0, 0, 1, 0) + # https://github.com/pytorch/vision/blob/0c2373d0bba3499e95776e7936e207d8a1676e65/torchvision/transforms/functional.py#L976 + img = F.affine( + img, + angle=0.0, + translate=[0, 0], + scale=1.0, + shear=[math.degrees(math.atan(magnitude)), 0.0], + interpolation=interpolation, + fill=fill, + center=[0, 0], + ) + elif op_name == "ShearY": + # magnitude should be arctan(magnitude) + # See above + img = F.affine( + img, + angle=0.0, + translate=[0, 0], + scale=1.0, + shear=[0.0, math.degrees(math.atan(magnitude))], + interpolation=interpolation, + fill=fill, + center=[0, 0], + ) + elif op_name == "TranslateX": + img = F.affine( + img, + angle=0.0, + translate=[int(magnitude), 0], + scale=1.0, + interpolation=interpolation, + shear=[0.0, 0.0], + fill=fill, + ) + elif op_name == "TranslateY": + img = F.affine( + img, + angle=0.0, + translate=[0, int(magnitude)], + scale=1.0, + interpolation=interpolation, + shear=[0.0, 0.0], + fill=fill, + ) + elif op_name == "Rotate": + img = F.rotate(img, magnitude, interpolation=interpolation, fill=fill) + elif op_name == "Brightness": + img = F.adjust_brightness(img, 1.0 + magnitude) + elif op_name == "Color": + img = F.adjust_saturation(img, 1.0 + magnitude) + elif op_name == "Contrast": + img = F.adjust_contrast(img, 1.0 + magnitude) + elif op_name == "Sharpness": + img = F.adjust_sharpness(img, 1.0 + magnitude) + elif op_name == "Posterize": + if torch.is_tensor(img): + img = T.ToPILImage()(img) + img = F.posterize(img, int(magnitude)) + img = T.ToTensor()(img) + else: + img = F.posterize(img, int(magnitude)) + elif op_name == "Solarize": + if torch.is_tensor(img): + img = T.ToPILImage()(img) + img = F.solarize(img, magnitude) + img = T.ToTensor()(img) + else: + img = F.solarize(img, magnitude) + elif op_name == "AutoContrast": + img = F.autocontrast(img) + elif op_name == "Equalize": + if torch.is_tensor(img): + img = T.ToPILImage()(img) + img = F.equalize(img) + img = T.ToTensor()(img) + else: + img = F.equalize(img) + elif op_name == "Invert": + img = F.invert(img) + elif op_name == "Identity": + pass + else: + raise ValueError(f"The provided operator {op_name} is not recognized.") + return img diff --git a/code/models/nyuv2_segnet_jtr.py b/code/models/nyuv2_segnet_jtr.py new file mode 100644 index 0000000..0d36aa9 --- /dev/null +++ b/code/models/nyuv2_segnet_jtr.py @@ -0,0 +1,294 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import copy +from utils.process import ( + preprocess_depth_gt, + preprocess_normal_gt, + preprocess_seg_gt, + preprocess_seg_pred, + get_jtr_mask_intersection_nyuv2, + preprocess_depth_pred, + preprocess_normal_pred, + get_recon_loss_depth, + get_recon_loss_normal, + get_recon_loss_seg, +) + + +class SegNet_JTR(nn.Module): + def __init__(self, channel_dims): + super(SegNet_JTR, self).__init__() + + self.channel_dims = channel_dims + self.num_tasks = len(self.channel_dims) + in_channels = sum(channel_dims) + + # initialise network parameters + filter = [64, 128, 256, 512, 512] + + # define encoder decoder layers + self.encoder_block = nn.ModuleList([self.conv_layer([in_channels, filter[0]])]) + self.decoder_block = nn.ModuleList([self.conv_layer([filter[0], filter[0]])]) + for i in range(4): + self.encoder_block.append(self.conv_layer([filter[i], filter[i + 1]])) + self.decoder_block.append(self.conv_layer([filter[i + 1], filter[i]])) + + # define convolution layer + self.conv_block_enc = nn.ModuleList([self.conv_layer([filter[0], filter[0]])]) + self.conv_block_dec = nn.ModuleList([self.conv_layer([filter[0], filter[0]])]) + for i in range(4): + if i == 0: + self.conv_block_enc.append( + self.conv_layer([filter[i + 1], filter[i + 1]]) + ) + self.conv_block_dec.append(self.conv_layer([filter[i], filter[i]])) + else: + self.conv_block_enc.append( + nn.Sequential( + self.conv_layer([filter[i + 1], filter[i + 1]]), + self.conv_layer([filter[i + 1], filter[i + 1]]), + ) + ) + self.conv_block_dec.append( + nn.Sequential( + self.conv_layer([filter[i], filter[i]]), + self.conv_layer([filter[i], filter[i]]), + ) + ) + + # define task specific layers + self.pred_layer = nn.Sequential( + nn.Conv2d( + in_channels=filter[0], out_channels=filter[0], kernel_size=3, padding=1 + ), + nn.Conv2d( + in_channels=filter[0], + out_channels=in_channels, + kernel_size=1, + padding=0, + ), + ) + + # define pooling and unpooling functions + self.down_sampling = nn.MaxPool2d(kernel_size=2, stride=2, return_indices=True) + self.up_sampling = nn.MaxUnpool2d(kernel_size=2, stride=2) + + self.batchnorm = nn.BatchNorm2d(num_features=in_channels) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.xavier_normal_(m.weight) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.xavier_normal_(m.weight) + nn.init.constant_(m.bias, 0) + + # define convolutional block + def conv_layer(self, channel): + conv_block = nn.Sequential( + nn.Conv2d( + in_channels=channel[0], + out_channels=channel[1], + kernel_size=3, + padding=1, + ), + nn.BatchNorm2d(num_features=channel[1]), + nn.ReLU(inplace=True), + ) + return conv_block + + def forward(self, x, return_feat_only=False): + g_encoder, g_decoder, g_maxpool, g_upsampl, indices = ( + [0] * 5 for _ in range(5) + ) + for i in range(5): + g_encoder[i], g_decoder[-i - 1] = ([0] * 2 for _ in range(2)) + + # global shared encoder-decoder network + for i in range(5): + if i == 0: + g_encoder[i][0] = self.encoder_block[i](x) + g_encoder[i][1] = self.conv_block_enc[i](g_encoder[i][0]) + g_maxpool[i], indices[i] = self.down_sampling(g_encoder[i][1]) + else: + g_encoder[i][0] = self.encoder_block[i](g_maxpool[i - 1]) + g_encoder[i][1] = self.conv_block_enc[i](g_encoder[i][0]) + g_maxpool[i], indices[i] = self.down_sampling(g_encoder[i][1]) + feat = [g_maxpool[i]] + if return_feat_only: + return feat[0] + # feat = [g_maxpool] + for i in range(5): + if i == 0: + g_upsampl[i] = self.up_sampling(g_maxpool[-1], indices[-i - 1]) + g_decoder[i][0] = self.decoder_block[-i - 1](g_upsampl[i]) + g_decoder[i][1] = self.conv_block_dec[-i - 1](g_decoder[i][0]) + else: + g_upsampl[i] = self.up_sampling(g_decoder[i - 1][-1], indices[-i - 1]) + g_decoder[i][0] = self.decoder_block[-i - 1](g_upsampl[i]) + g_decoder[i][1] = self.conv_block_dec[-i - 1](g_decoder[i][0]) + + feat.append(g_decoder[i][1]) + # feat.append(g_decoder) + + # define task prediction layers + t_pred = self.pred_layer(g_decoder[i][1]) + + return feat[0], t_pred + + def compute_losses( + self, + items_1, + items_2, + labeled_tasks, + num_classes, + recon_dist_weight, + ): + [ + train_pred_seg_1, + train_pred_depth_1, + train_pred_normal_1, + train_seg_1, + train_depth_1, + train_normal_1, + ] = [ + items_1[i].detach() if i in labeled_tasks else items_1[i] + for i in range(3 * 2) + ] + [ + train_pred_seg_2, + train_pred_depth_2, + train_pred_normal_2, + train_seg_2, + train_depth_2, + train_normal_2, + ] = [ + items_2[i].detach() if i in labeled_tasks else items_2[i] + for i in range(3 * 2) + ] + + mask_1 = get_jtr_mask_intersection_nyuv2( + train_seg_1, train_depth_1, train_normal_1, labeled_tasks + ) + mask_2 = get_jtr_mask_intersection_nyuv2( + train_seg_2, train_depth_2, train_normal_2, labeled_tasks + ) + + Y_hat_1 = torch.cat( + [ + preprocess_seg_pred(train_pred_seg_1, mask_1, hard=True), + preprocess_depth_pred(train_pred_depth_1, mask_1), + preprocess_normal_pred(train_pred_normal_1, mask_1), + ], + dim=1, + ) + Y_1 = torch.cat( + [ + ( + preprocess_seg_gt(train_seg_1, num_classes) + if 0 in labeled_tasks + else preprocess_seg_pred(train_pred_seg_1, mask_1, hard=True) + ), + ( + preprocess_depth_gt(train_depth_1) + if 1 in labeled_tasks + else preprocess_depth_pred(train_pred_depth_1, mask_1) + ), + ( + preprocess_normal_gt(train_normal_1) + if 2 in labeled_tasks + else preprocess_normal_pred(train_pred_normal_1, mask_1) + ), + ], + dim=1, + ) + Y_hat_2 = torch.cat( + [ + preprocess_seg_pred(train_pred_seg_2, mask_2), + preprocess_depth_pred(train_pred_depth_2, mask_2), + preprocess_normal_pred(train_pred_normal_2, mask_2), + ], + dim=1, + ) + Y_2 = torch.cat( + [ + ( + preprocess_seg_gt(train_seg_2, num_classes) + if 0 in labeled_tasks + else preprocess_seg_pred(train_pred_seg_2, mask_2, hard=True) + ), + ( + preprocess_depth_gt(train_depth_2) + if 1 in labeled_tasks + else preprocess_depth_pred(train_pred_depth_2, mask_2) + ), + ( + preprocess_normal_gt(train_normal_2) + if 2 in labeled_tasks + else preprocess_normal_pred(train_pred_normal_2, mask_2) + ), + ], + dim=1, + ) + + copied = copy.deepcopy(self) + + feat_Y_1 = copied(Y_1, return_feat_only=True) + feat_Y_hat_1 = copied(Y_hat_1, return_feat_only=True) + feat_Y_2, recon_Y_2 = self(Y_2.detach()) + feat_Y_hat_2, recon_Y_hat_2 = self(Y_hat_2.detach()) + recon_Y_2_seg, recon_Y_2_depth, recon_Y_2_normal = torch.split( + recon_Y_2, self.channel_dims, dim=1 + ) + recon_Y_hat_2_seg, recon_Y_hat_2_depth, recon_Y_hat_2_normal = torch.split( + recon_Y_hat_2, self.channel_dims, dim=1 + ) + + L_dist = ( + 1 - F.cosine_similarity(feat_Y_1, feat_Y_hat_1, dim=1, eps=1e-12).mean() + ) + recon_dist_weight * ( + 1 - F.cosine_similarity(feat_Y_2, feat_Y_hat_2, dim=1, eps=1e-12).mean() + ) + L_recon = ( + get_recon_loss_seg( + recon_Y_2_seg, + ( + preprocess_seg_gt(train_seg_2, num_classes) + if 0 in labeled_tasks + else preprocess_seg_pred(train_pred_seg_2, mask_2, hard=True) + ), + mask_2, + ) + + get_recon_loss_depth( + recon_Y_2_depth, + (train_depth_2 if 1 in labeled_tasks else train_pred_depth_2), + mask_2, + ) + + get_recon_loss_normal( + recon_Y_2_normal, + (train_normal_2 if 2 in labeled_tasks else train_pred_normal_2), + mask_2, + ) + + get_recon_loss_seg( + recon_Y_hat_2_seg, + preprocess_seg_pred(train_pred_seg_2, mask_2, hard=True), + mask_2, + ) + + get_recon_loss_depth( + recon_Y_hat_2_depth, + preprocess_depth_pred(train_pred_depth_2, mask_2), + mask_2, + ) + + get_recon_loss_normal( + recon_Y_hat_2_normal, + preprocess_normal_pred(train_pred_normal_2, mask_2), + mask_2, + ) + ) + + return L_dist, L_recon diff --git a/code/models/nyuv2_segnet_mtl.py b/code/models/nyuv2_segnet_mtl.py new file mode 100644 index 0000000..569b114 --- /dev/null +++ b/code/models/nyuv2_segnet_mtl.py @@ -0,0 +1,273 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math +from torch.autograd import Variable +import torch.nn.init as init +import numpy as np +import pdb + +# Define SegNet +# The implementation of SegNet is from https://github.com/lorenmt/mtan + + +class SegNet_MTL(nn.Module): + def __init__(self, num_classes=13): + super(SegNet_MTL, self).__init__() + + # initialise network parameters + filter = [64, 128, 256, 512, 512] + + self.num_classes = num_classes + + # define encoder decoder layers + self.encoder_block = nn.ModuleList([self.conv_layer([3, filter[0]])]) + self.decoder_block = nn.ModuleList([self.conv_layer([filter[0], filter[0]])]) + for i in range(4): + self.encoder_block.append(self.conv_layer([filter[i], filter[i + 1]])) + self.decoder_block.append(self.conv_layer([filter[i + 1], filter[i]])) + + # define convolution layer + self.conv_block_enc = nn.ModuleList([self.conv_layer([filter[0], filter[0]])]) + self.conv_block_dec = nn.ModuleList([self.conv_layer([filter[0], filter[0]])]) + for i in range(4): + if i == 0: + self.conv_block_enc.append( + self.conv_layer([filter[i + 1], filter[i + 1]]) + ) + self.conv_block_dec.append(self.conv_layer([filter[i], filter[i]])) + else: + self.conv_block_enc.append( + nn.Sequential( + self.conv_layer([filter[i + 1], filter[i + 1]]), + self.conv_layer([filter[i + 1], filter[i + 1]]), + ) + ) + self.conv_block_dec.append( + nn.Sequential( + self.conv_layer([filter[i], filter[i]]), + self.conv_layer([filter[i], filter[i]]), + ) + ) + + # define task specific layers + self.pred_task1 = nn.Sequential( + nn.Conv2d( + in_channels=filter[0], out_channels=filter[0], kernel_size=3, padding=1 + ), + nn.Conv2d( + in_channels=filter[0], + out_channels=self.num_classes, + kernel_size=1, + padding=0, + ), + ) + self.pred_task2 = nn.Sequential( + nn.Conv2d( + in_channels=filter[0], out_channels=filter[0], kernel_size=3, padding=1 + ), + nn.Conv2d(in_channels=filter[0], out_channels=1, kernel_size=1, padding=0), + ) + self.pred_task3 = nn.Sequential( + nn.Conv2d( + in_channels=filter[0], out_channels=filter[0], kernel_size=3, padding=1 + ), + nn.Conv2d(in_channels=filter[0], out_channels=3, kernel_size=1, padding=0), + ) + + # define pooling and unpooling functions + self.down_sampling = nn.MaxPool2d(kernel_size=2, stride=2, return_indices=True) + self.up_sampling = nn.MaxUnpool2d(kernel_size=2, stride=2) + + for m in self.modules(): + if isinstance(m, nn.Conv2d): + nn.init.xavier_normal_(m.weight) + if m.bias is not None: + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.BatchNorm2d): + nn.init.constant_(m.weight, 1) + nn.init.constant_(m.bias, 0) + elif isinstance(m, nn.Linear): + nn.init.xavier_normal_(m.weight) + nn.init.constant_(m.bias, 0) + + # define convolutional block + def conv_layer(self, channel): + conv_block = nn.Sequential( + nn.Conv2d( + in_channels=channel[0], + out_channels=channel[1], + kernel_size=3, + padding=1, + ), + nn.BatchNorm2d(num_features=channel[1]), + nn.ReLU(inplace=True), + ) + return conv_block + + def forward(self, x): + g_encoder, g_decoder, g_maxpool, g_upsampl, indices = ( + [0] * 5 for _ in range(5) + ) + for i in range(5): + g_encoder[i], g_decoder[-i - 1] = ([0] * 2 for _ in range(2)) + + # global shared encoder-decoder network + for i in range(5): + if i == 0: + g_encoder[i][0] = self.encoder_block[i](x) + g_encoder[i][1] = self.conv_block_enc[i](g_encoder[i][0]) + g_maxpool[i], indices[i] = self.down_sampling(g_encoder[i][1]) + else: + g_encoder[i][0] = self.encoder_block[i](g_maxpool[i - 1]) + g_encoder[i][1] = self.conv_block_enc[i](g_encoder[i][0]) + g_maxpool[i], indices[i] = self.down_sampling(g_encoder[i][1]) + feat = [g_maxpool[i]] + # feat = [g_maxpool] + for i in range(5): + if i == 0: + g_upsampl[i] = self.up_sampling(g_maxpool[-1], indices[-i - 1]) + g_decoder[i][0] = self.decoder_block[-i - 1](g_upsampl[i]) + g_decoder[i][1] = self.conv_block_dec[-i - 1](g_decoder[i][0]) + else: + g_upsampl[i] = self.up_sampling(g_decoder[i - 1][-1], indices[-i - 1]) + g_decoder[i][0] = self.decoder_block[-i - 1](g_upsampl[i]) + g_decoder[i][1] = self.conv_block_dec[-i - 1](g_decoder[i][0]) + + feat.append(g_decoder[i][1]) + # feat.append(g_decoder) + + # define task prediction layers + t1_pred = self.pred_task1(g_decoder[i][1]) + t2_pred = self.pred_task2(g_decoder[i][1]) + t3_pred = self.pred_task3(g_decoder[i][1]) + t3_pred = t3_pred / torch.norm(t3_pred, p=2, dim=1, keepdim=True) + + return [t1_pred, t2_pred, t3_pred], feat + + def compute_losses( + self, x_pred1, x_pred2, x_pred3, x_output1, x_output2, x_output3 + ): + # Compute supervised task-specific loss for all tasks when all task labels are available + + # binary mark to mask out undefined pixel space + binary_mask = ( + (torch.sum(x_output2, dim=1) != 0) + .type(torch.FloatTensor) + .unsqueeze(1) + .cuda() + ) + binary_mask_3 = ( + (torch.sum(x_output3, dim=1) != 0) + .type(torch.FloatTensor) + .unsqueeze(1) + .cuda() + ) + + # semantic loss: depth-wise cross entropy + loss1 = F.nll_loss(F.log_softmax(x_pred1, dim=1), x_output1, ignore_index=-1) + + # depth loss: l1 norm + loss2 = torch.sum(torch.abs(x_pred2 - x_output2) * binary_mask) / torch.nonzero( + binary_mask + ).size(0) + + # normal loss: dot product + loss3 = 1 - torch.sum((x_pred3 * x_output3) * binary_mask_3) / torch.nonzero( + binary_mask_3 + ).size(0) + + return [loss1, loss2, loss3] + + # evaluation metircs from https://github.com/lorenmt/mtan + def compute_miou(self, x_pred, x_output): + _, x_pred_label = torch.max(x_pred, dim=1) + x_output_label = x_output + batch_size = x_pred.size(0) + for i in range(batch_size): + true_class = 0 + first_switch = True + for j in range(self.num_classes): + pred_mask = torch.eq( + x_pred_label[i], + j * torch.ones(x_pred_label[i].shape).type(torch.LongTensor).cuda(), + ) + true_mask = torch.eq( + x_output_label[i], + j + * torch.ones(x_output_label[i].shape).type(torch.LongTensor).cuda(), + ) + mask_comb = pred_mask.type(torch.FloatTensor) + true_mask.type( + torch.FloatTensor + ) + union = torch.sum((mask_comb > 0).type(torch.FloatTensor)) + intsec = torch.sum((mask_comb > 1).type(torch.FloatTensor)) + if union == 0: + continue + if first_switch: + class_prob = intsec / union + first_switch = False + else: + class_prob = intsec / union + class_prob + true_class += 1 + if i == 0: + batch_avg = class_prob / true_class + else: + batch_avg = class_prob / true_class + batch_avg + return batch_avg / batch_size + + def compute_iou(self, x_pred, x_output): + _, x_pred_label = torch.max(x_pred, dim=1) + x_output_label = x_output + batch_size = x_pred.size(0) + for i in range(batch_size): + if i == 0: + pixel_acc = torch.div( + torch.sum( + torch.eq(x_pred_label[i], x_output_label[i]).type( + torch.FloatTensor + ) + ), + torch.sum((x_output_label[i] >= 0).type(torch.FloatTensor)), + ) + else: + pixel_acc = pixel_acc + torch.div( + torch.sum( + torch.eq(x_pred_label[i], x_output_label[i]).type( + torch.FloatTensor + ) + ), + torch.sum((x_output_label[i] >= 0).type(torch.FloatTensor)), + ) + return pixel_acc / batch_size + + def depth_error(self, x_pred, x_output): + binary_mask = (torch.sum(x_output, dim=1) != 0).unsqueeze(1).cuda() + x_pred_true = x_pred.masked_select(binary_mask) + x_output_true = x_output.masked_select(binary_mask) + abs_err = torch.abs(x_pred_true - x_output_true) + rel_err = torch.abs(x_pred_true - x_output_true) / x_output_true + return torch.sum(abs_err) / torch.nonzero(binary_mask).size(0), torch.sum( + rel_err + ) / torch.nonzero(binary_mask).size(0) + + def normal_error(self, x_pred, x_output): + binary_mask = torch.sum(x_output, dim=1) != 0 + error = ( + torch.acos( + torch.clamp( + torch.sum(x_pred * x_output, 1).masked_select(binary_mask), -1, 1 + ) + ) + .detach() + .cpu() + .numpy() + ) + error = np.degrees(error) + return ( + np.mean(error), + np.median(error), + np.mean(error < 11.25), + np.mean(error < 22.5), + np.mean(error < 30), + ) diff --git a/code/patches/mtpsl.patch b/code/patches/mtpsl.patch new file mode 100644 index 0000000..f22858a --- /dev/null +++ b/code/patches/mtpsl.patch @@ -0,0 +1,246 @@ +diff --git a/dataset/augmentation.py b/dataset/augmentation.py +new file mode 100644 +index 0000000..2dfe210 +--- /dev/null ++++ b/dataset/augmentation.py +@@ -0,0 +1,179 @@ ++###### ++# Augmentation on pytorch tensor ++###### ++import matplotlib.pyplot as plt ++import numpy as np ++import torch ++from torch import Tensor ++import torchvision.transforms as T ++from torchvision.transforms import functional as F, InterpolationMode ++from typing import Dict, List, Optional, Tuple ++ ++class ImgAugment(torch.nn.Module): ++ """ ++ Reference: RandAugment ++ https://pytorch.org/vision/main/_modules/torchvision/transforms/autoaugment.html#RandAugment ++ """ ++ def __init__( ++ self, ++ num_ops: int = 2, ++ magnitude: int = 6, # default 9, range from 0 ~ num_magnitude_bins ++ num_magnitude_bins: int = 31, # magnitude resolution ++ interpolation: InterpolationMode = InterpolationMode.NEAREST, ++ fill: Optional[List[float]] = None, ++ magnitude_sampling=True, ++ ) -> None: ++ super().__init__() ++ self.num_ops = num_ops ++ self.magnitude = magnitude ++ self.num_magnitude_bins = num_magnitude_bins ++ self.interpolation = interpolation ++ self.fill = fill ++ self.magnitude_sampling = magnitude_sampling ++ ++ def _augmentation_space(self, num_bins: int, image_size: Tuple[int, int]) -> Dict[str, Tuple[Tensor, bool]]: ++ return { ++ # op_name: (magnitudes, signed) ++ "Identity": (torch.tensor(0.0), False), ++ # "ShearX": (torch.linspace(0.0, 0.3, num_bins), True), ++ # "ShearY": (torch.linspace(0.0, 0.3, num_bins), True), ++ # "TranslateX": (torch.linspace(0.0, 150.0 / 331.0 * image_size[1], num_bins), True), ++ # "TranslateY": (torch.linspace(0.0, 150.0 / 331.0 * image_size[0], num_bins), True), ++ # "Rotate": (torch.linspace(0.0, 30.0, num_bins), True), ++ "Brightness": (torch.linspace(0.0, 0.9, num_bins), True), ++ "Color": (torch.linspace(0.0, 0.9, num_bins), True), ++ "Contrast": (torch.linspace(0.0, 0.9, num_bins), True), ++ "Sharpness": (torch.linspace(0.0, 0.9, num_bins), True), ++ "Posterize": (8 - (torch.arange(num_bins) / ((num_bins - 1) / 4)).round().int(), False), ++ "Solarize": (torch.linspace(255.0, 0.0, num_bins), False), ++ "AutoContrast": (torch.tensor(0.0), False), ++ "Equalize": (torch.tensor(0.0), False), ++ } ++ ++ def forward(self, img: Tensor) -> Tensor: ++ """ ++ img (PIL Image or Tensor): Image to be transformed. ++ ++ Returns: ++ PIL Image or Tensor: Transformed image. ++ """ ++ fill = self.fill ++ # channels, height, width = F.get_dimensions(img) ++ channels, height, width = img.shape ++ if isinstance(img, Tensor): ++ if isinstance(fill, (int, float)): ++ fill = [float(fill)] * channels ++ elif fill is not None: ++ fill = [float(f) for f in fill] ++ ++ op_meta = self._augmentation_space(self.num_magnitude_bins, (height, width)) ++ for _ in range(self.num_ops): ++ op_index = int(torch.randint(len(op_meta), (1,)).item()) ++ op_name = list(op_meta.keys())[op_index] ++ magnitudes, signed = op_meta[op_name] ++ if self.magnitude_sampling: ++ sampled_magnitude = torch.randint(self.magnitude, (1,)).item() ++ else: ++ sampled_magnitude = self.magnitude ++ magnitude = float(magnitudes[sampled_magnitude].item()) if magnitudes.ndim > 0 else 0.0 ++ if signed and torch.randint(2, (1,)): ++ magnitude *= -1.0 ++ img = _apply_op(img, op_name, magnitude, interpolation=self.interpolation, fill=fill) ++ ++ return img ++ ++ ++ ++def _apply_op( ++ img: Tensor, op_name: str, magnitude: float, interpolation: InterpolationMode, fill: Optional[List[float]] ++): ++ if op_name == "ShearX": ++ # magnitude should be arctan(magnitude) ++ # official autoaug: (1, level, 0, 0, 1, 0) ++ # https://github.com/tensorflow/models/blob/dd02069717128186b88afa8d857ce57d17957f03/research/autoaugment/augmentation_transforms.py#L290 ++ # compared to ++ # torchvision: (1, tan(level), 0, 0, 1, 0) ++ # https://github.com/pytorch/vision/blob/0c2373d0bba3499e95776e7936e207d8a1676e65/torchvision/transforms/functional.py#L976 ++ img = F.affine( ++ img, ++ angle=0.0, ++ translate=[0, 0], ++ scale=1.0, ++ shear=[math.degrees(math.atan(magnitude)), 0.0], ++ interpolation=interpolation, ++ fill=fill, ++ center=[0, 0], ++ ) ++ elif op_name == "ShearY": ++ # magnitude should be arctan(magnitude) ++ # See above ++ img = F.affine( ++ img, ++ angle=0.0, ++ translate=[0, 0], ++ scale=1.0, ++ shear=[0.0, math.degrees(math.atan(magnitude))], ++ interpolation=interpolation, ++ fill=fill, ++ center=[0, 0], ++ ) ++ elif op_name == "TranslateX": ++ img = F.affine( ++ img, ++ angle=0.0, ++ translate=[int(magnitude), 0], ++ scale=1.0, ++ interpolation=interpolation, ++ shear=[0.0, 0.0], ++ fill=fill, ++ ) ++ elif op_name == "TranslateY": ++ img = F.affine( ++ img, ++ angle=0.0, ++ translate=[0, int(magnitude)], ++ scale=1.0, ++ interpolation=interpolation, ++ shear=[0.0, 0.0], ++ fill=fill, ++ ) ++ elif op_name == "Rotate": ++ img = F.rotate(img, magnitude, interpolation=interpolation, fill=fill) ++ elif op_name == "Brightness": ++ img = F.adjust_brightness(img, 1.0 + magnitude) ++ elif op_name == "Color": ++ img = F.adjust_saturation(img, 1.0 + magnitude) ++ elif op_name == "Contrast": ++ img = F.adjust_contrast(img, 1.0 + magnitude) ++ elif op_name == "Sharpness": ++ img = F.adjust_sharpness(img, 1.0 + magnitude) ++ elif op_name == "Posterize": ++ if torch.is_tensor(img): ++ img = T.ToPILImage()(img) ++ img = F.posterize(img, int(magnitude)) ++ img = T.ToTensor()(img) ++ else: ++ img = F.posterize(img, int(magnitude)) ++ elif op_name == "Solarize": ++ if torch.is_tensor(img): ++ img = T.ToPILImage()(img) ++ img = F.solarize(img, magnitude) ++ img = T.ToTensor()(img) ++ else: ++ img = F.solarize(img, magnitude) ++ elif op_name == "AutoContrast": ++ img = F.autocontrast(img) ++ elif op_name == "Equalize": ++ if torch.is_tensor(img): ++ img = T.ToPILImage()(img) ++ img = F.equalize(img) ++ img = T.ToTensor()(img) ++ else: ++ img = F.equalize(img) ++ elif op_name == "Invert": ++ img = F.invert(img) ++ elif op_name == "Identity": ++ pass ++ else: ++ raise ValueError(f"The provided operator {op_name} is not recognized.") ++ return img +diff --git a/dataset/nyuv2ssl.py b/dataset/nyuv2ssl.py +index ecebd7f..916cc9f 100644 +--- a/dataset/nyuv2ssl.py ++++ b/dataset/nyuv2ssl.py +@@ -9,7 +9,7 @@ import torchvision.transforms as transforms + from PIL import Image + import random + import torch.nn.functional as F +- ++from dataset.augmentation import ImgAugment + + + class RandomScaleCrop(object): +@@ -77,6 +77,7 @@ class NYUv2_crop(Dataset): + self.root = os.path.expanduser(root) + self.augmentation = augmentation + self.aug_twice = aug_twice ++ self.augmenter = ImgAugment(num_ops = 2, magnitude = 6, num_magnitude_bins=31, magnitude_sampling=True) + + + # R\read the data file +@@ -102,6 +103,8 @@ class NYUv2_crop(Dataset): + elif self.augmentation and self.aug_twice: + image, semantic, depth, normal, _ = RandomScaleCrop()(image, semantic, depth, normal) + image1, semantic1, depth1, normal1, trans_params = RandomScaleCrop()(image, semantic, depth, normal) ++ image = self.augmenter(image) ++ image1 = self.augmenter(image1) + return image.type(torch.FloatTensor), semantic.type(torch.FloatTensor), depth.type(torch.FloatTensor), normal.type(torch.FloatTensor), index, image1.type(torch.FloatTensor), semantic1.type(torch.FloatTensor), depth1.type(torch.FloatTensor), normal1.type(torch.FloatTensor), trans_params + if self.train: + return image.type(torch.FloatTensor), semantic.type(torch.FloatTensor), depth.type(torch.FloatTensor), normal.type(torch.FloatTensor), index +diff --git a/nyu_mtl_xtc.py b/nyu_mtl_xtc.py +index e81799a..f9f1748 100644 +--- a/nyu_mtl_xtc.py ++++ b/nyu_mtl_xtc.py +@@ -110,7 +110,7 @@ elif opt.ssl_type == 'randomlabels': + nyuv2_train_set = NYUv2_crop(root=dataset_path, train=True, augmentation=True, aug_twice=True) + nyuv2_test_set = NYUv2(root=dataset_path, train=False) + +-batch_size = 2 ++batch_size = 4 + nyuv2_train_loader = torch.utils.data.DataLoader( + dataset=nyuv2_train_set, + batch_size=batch_size, +@@ -162,7 +162,7 @@ for epoch in range(start_epoch, total_epoch): + cost_normal = AverageMeter() + nyuv2_train_dataset = iter(nyuv2_train_loader) + for k in range(train_batch): +- train_data, train_label, train_depth, train_normal, image_index, train_data1, train_label1, train_depth1, train_normal1, trans_params = nyuv2_train_dataset.next() ++ train_data, train_label, train_depth, train_normal, image_index, train_data1, train_label1, train_depth1, train_normal1, trans_params = next(nyuv2_train_dataset) + train_data, train_label = train_data.cuda(), train_label.type(torch.LongTensor).cuda() + train_depth, train_normal = train_depth.cuda(), train_normal.cuda() + train_data1, train_label1 = train_data1.cuda(), train_label1.type(torch.LongTensor).cuda() +@@ -264,7 +264,7 @@ for epoch in range(start_epoch, total_epoch): + with torch.no_grad(): # operations inside don't track history + nyuv2_test_dataset = iter(nyuv2_test_loader) + for k in range(test_batch): +- test_data, test_label, test_depth, test_normal = nyuv2_test_dataset.next() ++ test_data, test_label, test_depth, test_normal = next(nyuv2_test_dataset) + test_data, test_label = test_data.cuda(), test_label.type(torch.LongTensor).cuda() + test_depth, test_normal = test_depth.cuda(), test_normal.cuda() + diff --git a/code/train_nyuv2.py b/code/train_nyuv2.py new file mode 100644 index 0000000..2e359d2 --- /dev/null +++ b/code/train_nyuv2.py @@ -0,0 +1,259 @@ +if __name__ == "__main__": + import os + import torch + import torch.optim as optim + from utils import * + from models.nyuv2_segnet_mtl import SegNet_MTL + from models.nyuv2_segnet_jtr import SegNet_JTR + from datasets.nyuv2 import NYUv2_MTL + from torch.utils.data import DataLoader + from tqdm import tqdm + + parser = get_base_arg_parser("JTR NYUv2 onelabel/randomlabels", {"batch_size": 4}) + + parser.add_argument( + "--ssl-type", + required=True, + type=str, + help="type of ssl", + ) + parser.add_argument( + "--seg-baseline", required=True, type=float, help="Seg. Baseline" + ) + parser.add_argument( + "--depth-baseline", required=True, type=float, help="Depth Baseline" + ) + parser.add_argument( + "--norm-baseline", required=True, type=float, help="Norm. Baseline" + ) + args = parser.parse_args() + num_classes = 13 + channel_dims = [num_classes, 1, 3] + + torch.manual_seed(args.seed) + torch.cuda.manual_seed(args.seed) + + logger = get_logger_nyuv2() + mkdir_recursive(args.out_dir) + model = SegNet_MTL().cuda() + jtr = SegNet_JTR(channel_dims).cuda() + + params = list(model.parameters()) + list(jtr.parameters()) + optimizer = optim.Adam(params, lr=1e-4) + scheduler = optim.lr_scheduler.StepLR( + optimizer, step_size=args.step_size, gamma=0.5 + ) + + label_weights = ( + torch.load(os.path.join(args.label_dir, f"{args.ssl_type}.pth"))[ + "labels_weights" + ] + .float() + .cuda() + ) + nyuv2_train_set = NYUv2_MTL( + root=args.data_dir, + train=True, + ) + nyuv2_train_loader = DataLoader( + nyuv2_train_set, + batch_size=args.batch_size, + shuffle=True, + num_workers=args.num_workers, + ) + nyuv2_test_set = NYUv2_MTL( + root=args.data_dir, + train=False, + ) + nyuv2_test_loader = DataLoader( + nyuv2_test_set, + batch_size=args.batch_size, + shuffle=False, + num_workers=args.num_workers, + ) + + best_delta_mtl = float("-inf") + for epoch in range(args.num_epochs): + bar = tqdm(nyuv2_train_loader) + model.train() + jtr.train() + for batch_idx, ( + train_idx, + train_input_0, + train_seg_0, + train_depth_0, + train_normal_0, + train_input_1, + train_seg_1, + train_depth_1, + train_normal_1, + train_input_2, + train_seg_2, + train_depth_2, + train_normal_2, + ) in enumerate(bar): + bar.set_description(f"Epoch {epoch}") + ( + train_input_0, + train_seg_0, + train_depth_0, + train_normal_0, + train_input_1, + train_seg_1, + train_depth_1, + train_normal_1, + train_input_2, + train_seg_2, + train_depth_2, + train_normal_2, + ) = ( + train_input_0.cuda(), + train_seg_0.type(torch.LongTensor).cuda(), + train_depth_0.cuda(), + train_normal_0.cuda(), + train_input_1.cuda(), + train_seg_1.type(torch.LongTensor).cuda(), + train_depth_1.cuda(), + train_normal_1.cuda(), + train_input_2.cuda(), + train_seg_2.type(torch.LongTensor).cuda(), + train_depth_2.cuda(), + train_normal_2.cuda(), + ) + train_data_cat = torch.cat( + (train_input_0, train_input_1, train_input_2), dim=0 + ) + train_pred_cat, _ = model(train_data_cat) + train_pred_0, train_pred_1, train_pred_2 = torch.split( + torch.cat(train_pred_cat, dim=1), train_idx.size(0), dim=0 + ) + + loss = torch.tensor(0.0, requires_grad=True).cuda() + + for ind in range(train_idx.size(0)): + w = label_weights[train_idx[ind].item()].clone().float().cuda() + labeled_tasks = torch.nonzero(w).squeeze(1).tolist() + train_pred_seg_0, train_pred_depth_0, train_pred_normal_0 = torch.split( + train_pred_0[ind].unsqueeze(0), channel_dims, dim=1 + ) + train_pred_seg_1, train_pred_depth_1, train_pred_normal_1 = torch.split( + train_pred_1[ind].unsqueeze(0), channel_dims, dim=1 + ) + train_pred_seg_2, train_pred_depth_2, train_pred_normal_2 = torch.split( + train_pred_2[ind].unsqueeze(0), channel_dims, dim=1 + ) + train_losses = model.compute_losses( + train_pred_seg_0, + train_pred_depth_0, + train_pred_normal_0, + train_seg_0[ind].unsqueeze(0), + train_depth_0[ind].unsqueeze(0), + train_normal_0[ind].unsqueeze(0), + ) + L_sl = sum([train_losses[i] for i in labeled_tasks]) / train_idx.size(0) + + L_dist, L_recon = jtr.compute_losses( + ( + train_pred_seg_1, + train_pred_depth_1, + train_pred_normal_1, + train_seg_1[ind].unsqueeze(0), + train_depth_1[ind].unsqueeze(0), + train_normal_1[ind].unsqueeze(0), + ), + ( + train_pred_seg_2, + train_pred_depth_2, + train_pred_normal_2, + train_seg_2[ind].unsqueeze(0), + train_depth_2[ind].unsqueeze(0), + train_normal_2[ind].unsqueeze(0), + ), + labeled_tasks, + num_classes, + args.recon_weight, + ) + + L_jtr = ( + args.dist_mtl_weight * L_dist + args.recon_weight * L_recon + ) / train_idx.size(0) + + loss += L_sl + L_jtr + + optimizer.zero_grad() + loss.backward() + optimizer.step() + + model.eval() + conf_matrix = ConfMatrix(num_classes) + depth_meter = DepthMeter() + normal_meter = NormalsMeter() + with torch.no_grad(): + for ( + test_input, + test_seg, + test_depth, + test_normal, + ) in nyuv2_test_loader: + test_input, test_seg, test_depth, test_normal = ( + test_input.cuda(), + test_seg.type(torch.LongTensor).cuda(), + test_depth.cuda(), + test_normal.cuda(), + ) + test_pred, _ = model(test_input) + test_pred_seg, test_pred_depth, test_pred_normal = test_pred + conf_matrix.update( + test_pred_seg.argmax(1).flatten(), test_seg.flatten() + ) + depth_meter.update(test_pred_depth, test_depth) + normal_meter.update(test_pred_normal, test_normal) + v_miou, v_acc = conf_matrix.get_metrics() + v_depth_scores = depth_meter.get_score() + v_l1, v_rel = v_depth_scores["l1"], v_depth_scores["rmse"] + v_normal_scores = normal_meter.get_score() + v_mean, v_med, v_11_25, v_22_5, v_30 = ( + v_normal_scores["mean"], + v_normal_scores["rmse"], + v_normal_scores["11.25"], + v_normal_scores["22.5"], + v_normal_scores["30"], + ) + delta_seg, delta_depth, delta_norm, delta_mtl = compute_delta_mtl_nyuv2( + v_miou, + v_l1, + v_mean, + args.seg_baseline, + args.depth_baseline, + args.norm_baseline, + ) + is_best = delta_mtl > best_delta_mtl + best_delta_mtl = max(delta_mtl, best_delta_mtl) + info = [ + v_miou, + v_acc, + v_l1, + v_rel, + v_mean, + v_med, + v_11_25, + v_22_5, + v_30, + delta_seg, + delta_depth, + delta_norm, + delta_mtl, + best_delta_mtl, + ] + write_logger(logger, epoch, info, args.out_dir, "logs.csv") + save_checkpoint( + args.out_dir, + { + "epoch": epoch, + "model_state_dict": model.state_dict(), + "optimizer": optimizer.state_dict(), + "scheduler": scheduler.state_dict(), + }, + is_best, + ) + scheduler.step() diff --git a/code/utils/__init__.py b/code/utils/__init__.py new file mode 100644 index 0000000..4383e9c --- /dev/null +++ b/code/utils/__init__.py @@ -0,0 +1,6 @@ +from .cli import * +from .files import * +from .evals import * +from .gumbel import * +from .process import * +from .deltas import * diff --git a/code/utils/cli.py b/code/utils/cli.py new file mode 100644 index 0000000..426a5e7 --- /dev/null +++ b/code/utils/cli.py @@ -0,0 +1,27 @@ +import argparse +from typing import Dict + + +def get_base_arg_parser(description, arg_values: Dict) -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description=description) + + parser.add_argument("--data-dir", required=True, type=str, help="path to dataset") + parser.add_argument( + "--out-dir", required=True, type=str, help="path to output directory" + ) + parser.add_argument( + "--label-dir", required=True, type=str, help="path to label dir" + ) + parser.add_argument( + "--dist-mtl-weight", default=4, type=float, help="dist_mtl_weight" + ) + parser.add_argument("--recon-weight", default=2, type=float, help="recon_weight") + parser.add_argument("--num-epochs", default=400, type=int, help="num_epochs") + parser.add_argument("--step-size", default=200, type=int, help="step_size") + parser.add_argument( + "--batch-size", default=arg_values["batch_size"], type=int, help="batch_size" + ) + parser.add_argument("--num-workers", default=4, type=int, help="num_workers") + parser.add_argument("--seed", default=0, type=int, help="seed") + + return parser diff --git a/code/utils/deltas.py b/code/utils/deltas.py new file mode 100644 index 0000000..678b1a1 --- /dev/null +++ b/code/utils/deltas.py @@ -0,0 +1,17 @@ +def compute_delta_mtl_nyuv2( + seg, depth, normal, seg_baseline, depth_baseline, normal_baseline +): + seg_delta = (seg * 100 - seg_baseline) / seg_baseline + depth_delta = (depth_baseline - depth) / depth_baseline + normal_delta = (normal_baseline - normal) / normal_baseline + delta_mtl = (seg_delta + depth_delta + normal_delta) / 3 + + return seg_delta, depth_delta, normal_delta, delta_mtl + + +def compute_delta_mtl_cityscapes(seg, depth, seg_baseline, depth_baseline): + seg_delta = (seg * 100 - seg_baseline) / seg_baseline + depth_delta = (depth_baseline - depth) / depth_baseline + delta_mtl = (seg_delta + depth_delta) / 2 + + return seg_delta, depth_delta, delta_mtl diff --git a/code/utils/evals.py b/code/utils/evals.py new file mode 100644 index 0000000..1b85512 --- /dev/null +++ b/code/utils/evals.py @@ -0,0 +1,135 @@ +import torch +import torch.nn as nn +import torch.nn.functional as F +import math +from torch.autograd import Variable +import torch.nn.init as init +import numpy as np +import pdb + +# Updated evaluation metrics from https://github.com/lorenmt/mtan and from the SOTA paper https://github.com/SimonVandenhende/Multi-Task-Learning-PyTorch + + +class ConfMatrix(object): + def __init__(self, num_classes): + self.num_classes = num_classes + self.mat = None + + def update(self, pred, target): + n = self.num_classes + if self.mat is None: + self.mat = torch.zeros((n, n), dtype=torch.int64, device=pred.device) + with torch.no_grad(): + k = (target >= 0) & (target < n) + inds = n * target[k].to(torch.int64) + pred[k] + self.mat += torch.bincount(inds, minlength=n**2).reshape(n, n) + + def get_metrics(self): + h = self.mat.float() + acc = torch.diag(h).sum() / h.sum() + iu = torch.diag(h) / (h.sum(1) + h.sum(0) - torch.diag(h)) + return torch.mean(iu).cpu().numpy(), acc.cpu().numpy() + + +class NormalsMeter(object): + def __init__(self): + self.eval_dict = { + "mean": 0.0, + "rmse": 0.0, + "11.25": 0.0, + "22.5": 0.0, + "30": 0.0, + "n": 0, + } + + @torch.no_grad() + def update(self, pred, gt): + # Performance measurement happens in pixel wise fashion (Same as code from ASTMT (above)) + valid_mask = torch.sum(gt, dim=1) != 0 + invalid_mask = torch.sum(gt, dim=1) == 0 + + # Calculate difference expressed in degrees + deg_diff_tmp = (180 / math.pi) * ( + torch.acos( + torch.clamp( + torch.sum(pred * gt, 1).masked_select(valid_mask), min=-1, max=1 + ) + ) + ) + + self.eval_dict["mean"] += torch.sum(deg_diff_tmp).item() + self.eval_dict["rmse"] += torch.sum(torch.pow(deg_diff_tmp, 2)).item() + self.eval_dict["11.25"] += ( + torch.sum((deg_diff_tmp < 11.25).float()).item() * 100 + ) + self.eval_dict["22.5"] += torch.sum((deg_diff_tmp < 22.5).float()).item() * 100 + self.eval_dict["30"] += torch.sum((deg_diff_tmp < 30).float()).item() * 100 + self.eval_dict["n"] += deg_diff_tmp.numel() + + def reset(self): + self.eval_dict = { + "mean": 0.0, + "rmse": 0.0, + "11.25": 0.0, + "22.5": 0.0, + "30": 0.0, + "n": 0, + } + + def get_score(self, verbose=True): + eval_result = dict() + eval_result["mean"] = self.eval_dict["mean"] / self.eval_dict["n"] + eval_result["rmse"] = np.sqrt(self.eval_dict["rmse"] / self.eval_dict["n"]) + eval_result["11.25"] = self.eval_dict["11.25"] / self.eval_dict["n"] + eval_result["22.5"] = self.eval_dict["22.5"] / self.eval_dict["n"] + eval_result["30"] = self.eval_dict["30"] / self.eval_dict["n"] + + return eval_result + + +class DepthMeter(object): + def __init__(self): + self.total_rmses = 0.0 + self.total_l1 = 0.0 + self.total_log_rmses = 0.0 + self.n_valid = 0.0 + self.num_images = 0.0 + self.n_valid_image = [] + self.rmses = [] + + @torch.no_grad() + def update(self, pred, gt): + pred, gt = pred.squeeze(), gt.squeeze() + self.num_images += pred.size(0) + + # Determine valid mask + mask = (gt != 0).bool() + self.n_valid += mask.float().sum().item() # Valid pixels per image + + # Only positive depth values are possible + pred = torch.clamp(pred, min=1e-9) + + # Per pixel rmse and log-rmse. + log_rmse_tmp = torch.pow(torch.log(gt) - torch.log(pred), 2) + log_rmse_tmp = torch.masked_select(log_rmse_tmp, mask) + self.total_log_rmses += log_rmse_tmp.sum().item() + + pred = pred.masked_select(mask) + gt = gt.masked_select(mask) + rmse_tmp = (gt - pred).abs().pow(2).cpu() + + l1_tmp = (gt - pred).abs() + self.total_rmses += rmse_tmp.sum().item() + self.total_l1 += l1_tmp.sum().item() + + def reset(self): + self.rmses = [] + self.log_rmses = [] + + def get_score(self, verbose=True): + eval_result = dict() + eval_result["rmse"] = np.sqrt(self.total_rmses / self.n_valid) + eval_result["l1"] = self.total_l1 / self.n_valid + eval_result["log_rmse"] = np.sqrt(self.total_log_rmses / self.n_valid) + + return eval_result diff --git a/code/utils/files.py b/code/utils/files.py new file mode 100644 index 0000000..f2cd32e --- /dev/null +++ b/code/utils/files.py @@ -0,0 +1,64 @@ +import os +import torch +import shutil +from pandas import DataFrame + + +def mkdir_recursive(path): + if not os.path.exists(path): + os.makedirs(path) + + +def save_checkpoint(base, state, is_best, filename="checkpoint.pth.tar"): + filename = os.path.join(base, filename) + torch.save(state, filename) + if is_best: + shutil.copyfile(filename, os.path.join(base, "model_best.pth.tar")) + + +def get_logger_nyuv2(): + df = DataFrame( + columns=[ + "Epoch", + "V. Seg. mIoU", + "V. Seg. Acc.", + "V. Depth Abs.", + "V. Depth Rel.", + "V. Norm. Mean", + "V. Norm. Med.", + "V. Norm. 11.25", + "V. Norm. 22.5", + "V. Norm. 30", + "V. Delta Seg.", + "V. Delta Depth", + "V. Delta Norm.", + "V. Delta MTL", + "Best Delta MTL", + ] + ) + return df + + +def get_logger_cityscapes(): + df = DataFrame( + columns=[ + "Epoch", + "V. Seg. mIoU", + "V. Seg. Acc.", + "V. Depth Abs.", + "V. Depth Rel.", + "V. Delta Seg.", + "V. Delta Depth", + "V. Delta MTL", + "Best Delta MTL", + ] + ) + return df + + +def write_logger(logger, epoch, info, base, filename="logs.csv"): + logger.loc[epoch] = [ + epoch, + *info, + ] + logger.to_csv(os.path.join(base, filename), index=False) diff --git a/code/utils/gumbel.py b/code/utils/gumbel.py new file mode 100644 index 0000000..42ac46a --- /dev/null +++ b/code/utils/gumbel.py @@ -0,0 +1,60 @@ +import torch +import torch.nn.functional as F + + +def gumbel_softmax(logits, tau=1, hard=False, eps=1e-10, dim=-1): + # type: (Tensor, float, bool, float, int) -> Tensor + r""" + Samples from the `Gumbel-Softmax distribution`_ and optionally discretizes. + You can use this function to replace "F.gumbel_softmax". + + Args: + logits: `[..., num_features]` unnormalized log probabilities + tau: non-negative scalar temperature + hard: if ``True``, the returned samples will be discretized as one-hot vectors, + but will be differentiated as if it is the soft sample in autograd + dim (int): A dimension along which softmax will be computed. Default: -1. + Returns: + Sampled tensor of same shape as `logits` from the Gumbel-Softmax distribution. + If ``hard=True``, the returned samples will be one-hot, otherwise they will + be probability distributions that sum to 1 across `dim`. + .. note:: + This function is here for legacy reasons, may be removed from nn.Functional in the future. + .. note:: + The main trick for `hard` is to do `y_hard - y_soft.detach() + y_soft` + It achieves two things: + - makes the output value exactly one-hot + (since we add then subtract y_soft value) + - makes the gradient equal to y_soft gradient + (since we strip all other gradients) + Examples:: + >>> logits = torch.randn(20, 32) + >>> # Sample soft categorical using reparametrization trick: + >>> F.gumbel_softmax(logits, tau=1, hard=False) + >>> # Sample hard categorical using "Straight-through" trick: + >>> F.gumbel_softmax(logits, tau=1, hard=True) + .. _Gumbel-Softmax distribution: + https://arxiv.org/abs/1611.00712 + https://arxiv.org/abs/1611.01144 + """ + + def _gen_gumbels(): + gumbels = -torch.empty_like(logits).exponential_().log() + if torch.isnan(gumbels).sum() or torch.isinf(gumbels).sum(): + # to avoid zero in exp output + gumbels = _gen_gumbels() + return gumbels + + gumbels = _gen_gumbels() # ~Gumbel(0,1) + gumbels = (logits + gumbels) / tau # ~Gumbel(logits,tau) + y_soft = gumbels.softmax(dim) + + if hard: + # Straight through. + index = y_soft.max(dim, keepdim=True)[1] + y_hard = torch.zeros_like(logits).scatter_(dim, index, 1.0) + ret = y_hard - y_soft.detach() + y_soft + else: + # Reparametrization trick. + ret = y_soft + return ret diff --git a/code/utils/process.py b/code/utils/process.py new file mode 100644 index 0000000..bfc898e --- /dev/null +++ b/code/utils/process.py @@ -0,0 +1,110 @@ +import torch +import torch.nn.functional as F +from .gumbel import gumbel_softmax + +_avg = 2.3618 +_std = 1.5876 + +d = torch.distributions.normal.Normal(_avg, _std) + + +def _transform(x): + return d.cdf(x) + + +def _gumbel(pred): + return gumbel_softmax(pred, dim=1, tau=1, hard=True) + + +def preprocess_seg_pred(pred, mask, hard=False): + return (_gumbel(pred) if hard else F.softmax(pred, dim=1)) * mask + + +def preprocess_depth_pred(pred, mask): + return _transform(pred * mask) + + +def preprocess_normal_pred(pred, mask): + return (pred * mask + 1.0) / 2.0 + + +def get_mask_seg_gt(y): + return (y != -1).type(torch.LongTensor).cuda().unsqueeze(0).detach() + + +def get_mask_depth_gt(y): + return ( + (torch.sum(y, dim=1) != 0).type(torch.LongTensor).cuda().unsqueeze(1).detach() + ) + + +def get_mask_normal_gt(y): + return ( + (torch.sum(y, dim=1) != 0).type(torch.LongTensor).cuda().unsqueeze(1).detach() + ) + + +def get_jtr_mask_intersection_nyuv2(seg_gt, depth_gt, normal_gt, labeled_tasks): + mask = torch.ones_like(seg_gt.unsqueeze(0)) + if 0 in labeled_tasks: + mask *= get_mask_seg_gt(seg_gt) + if 1 in labeled_tasks: + mask *= get_mask_depth_gt(depth_gt) + if 2 in labeled_tasks: + mask *= get_mask_normal_gt(normal_gt) + return mask.detach() + +def get_jtr_mask_intersection_cityscapes(seg_gt, depth_gt, labeled_tasks): + mask = torch.ones_like(seg_gt.unsqueeze(0)) + if 0 in labeled_tasks: + mask *= get_mask_seg_gt(seg_gt) + if 1 in labeled_tasks: + mask *= get_mask_depth_gt(depth_gt) + return mask.detach() + +def preprocess_seg_gt(y, num_classes): + y = y.unsqueeze(0) + binary_mask = (y == -1).type(torch.FloatTensor).cuda() + y_1 = y.float() * (1 - binary_mask) + y_2 = torch.zeros(y.size(0), num_classes, y.size(2), y.size(3)).scatter_( + 1, y_1.type(torch.LongTensor), 1 + ).cuda().detach() * (1 - binary_mask) + return y_2 + + +def preprocess_depth_gt(y): + binary_mask = get_mask_depth_gt(y) + return _transform(y * binary_mask) + + +def preprocess_normal_gt(y): + return (y + 1.0) / 2.0 + + +def _get_detached_and_size(x): + return x.detach(), x.nonzero().size(0) + + +def get_recon_loss_seg(x_pred, x_output, mask): + x_output, mask_size = _get_detached_and_size(x_output) + return ( + F.binary_cross_entropy_with_logits(x_pred, x_output, reduction="none") * mask + ).sum() / mask_size + + +def get_recon_loss_depth(x_pred, x_output, mask): + x_output, mask_size = _get_detached_and_size(x_output) + x_pred = (torch.sigmoid(x_pred) - 0.5) * (1 - 1e-5) + 0.5 + x_output = _transform(x_output) + return (F.l1_loss(x_pred, x_output, reduction="none") * mask).sum() / mask_size + + +def get_recon_loss_normal(x_pred, x_output, mask): + x_output, mask_size = _get_detached_and_size(x_output) + return ( + 1 + - torch.sum( + ((x_pred / torch.norm(x_pred, p=2, dim=1, keepdim=True)) * x_output * mask) + ) + / mask_size + ) diff --git a/website/.eslintignore b/website/.eslintignore new file mode 100644 index 0000000..3897265 --- /dev/null +++ b/website/.eslintignore @@ -0,0 +1,13 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example + +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/website/.eslintrc.cjs b/website/.eslintrc.cjs new file mode 100644 index 0000000..0b75758 --- /dev/null +++ b/website/.eslintrc.cjs @@ -0,0 +1,31 @@ +/** @type { import("eslint").Linter.Config } */ +module.exports = { + root: true, + extends: [ + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'plugin:svelte/recommended', + 'prettier' + ], + parser: '@typescript-eslint/parser', + plugins: ['@typescript-eslint'], + parserOptions: { + sourceType: 'module', + ecmaVersion: 2020, + extraFileExtensions: ['.svelte'] + }, + env: { + browser: true, + es2017: true, + node: true + }, + overrides: [ + { + files: ['*.svelte'], + parser: 'svelte-eslint-parser', + parserOptions: { + parser: '@typescript-eslint/parser' + } + } + ] +}; diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000..6635cf5 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,10 @@ +.DS_Store +node_modules +/build +/.svelte-kit +/package +.env +.env.* +!.env.example +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/website/.npmrc b/website/.npmrc new file mode 100644 index 0000000..b6f27f1 --- /dev/null +++ b/website/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/website/.prettierignore b/website/.prettierignore new file mode 100644 index 0000000..cc41cea --- /dev/null +++ b/website/.prettierignore @@ -0,0 +1,4 @@ +# Ignore files for PNPM, NPM and YARN +pnpm-lock.yaml +package-lock.json +yarn.lock diff --git a/website/.prettierrc b/website/.prettierrc new file mode 100644 index 0000000..9573023 --- /dev/null +++ b/website/.prettierrc @@ -0,0 +1,8 @@ +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte"], + "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] +} diff --git a/website/README.md b/website/README.md new file mode 100644 index 0000000..5ce6766 --- /dev/null +++ b/website/README.md @@ -0,0 +1,38 @@ +# create-svelte + +Everything you need to build a Svelte project, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npm create svelte@latest + +# create a new project in my-app +npm create svelte@latest my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment. diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000..48313fb --- /dev/null +++ b/website/package.json @@ -0,0 +1,37 @@ +{ + "name": "website", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "lint": "prettier --check . && eslint .", + "format": "prettier --write ." + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/adapter-static": "^3.0.1", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@types/eslint": "^8.56.0", + "@typescript-eslint/eslint-plugin": "^7.0.0", + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^5.0.3" + }, + "type": "module", + "dependencies": { + "exio": "^0.6.45" + } +} diff --git a/website/src/app.d.ts b/website/src/app.d.ts new file mode 100644 index 0000000..743f07b --- /dev/null +++ b/website/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://kit.svelte.dev/docs/types#app +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/website/src/app.html b/website/src/app.html new file mode 100644 index 0000000..14a3eb4 --- /dev/null +++ b/website/src/app.html @@ -0,0 +1,38 @@ + + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + + diff --git a/website/src/lib/assets/Poster.pdf b/website/src/lib/assets/Poster.pdf new file mode 100644 index 0000000..30d533d Binary files /dev/null and b/website/src/lib/assets/Poster.pdf differ diff --git a/website/src/lib/assets/Poster.png b/website/src/lib/assets/Poster.png new file mode 100644 index 0000000..b88e252 Binary files /dev/null and b/website/src/lib/assets/Poster.png differ diff --git a/website/src/lib/assets/overview.png b/website/src/lib/assets/overview.png new file mode 100644 index 0000000..972d703 Binary files /dev/null and b/website/src/lib/assets/overview.png differ diff --git a/website/src/lib/assets/teaser.png b/website/src/lib/assets/teaser.png new file mode 100644 index 0000000..6bb5fcf Binary files /dev/null and b/website/src/lib/assets/teaser.png differ diff --git a/website/src/lib/components/Banner.svelte b/website/src/lib/components/Banner.svelte new file mode 100644 index 0000000..61bf25c --- /dev/null +++ b/website/src/lib/components/Banner.svelte @@ -0,0 +1,132 @@ + + + + + diff --git a/website/src/lib/components/Loading.svelte b/website/src/lib/components/Loading.svelte new file mode 100644 index 0000000..2c39a77 --- /dev/null +++ b/website/src/lib/components/Loading.svelte @@ -0,0 +1,30 @@ + + +
+ +
diff --git a/website/src/lib/components/Summary.svelte b/website/src/lib/components/Summary.svelte new file mode 100644 index 0000000..67c9bbc --- /dev/null +++ b/website/src/lib/components/Summary.svelte @@ -0,0 +1,112 @@ + + +
+
TL;DR
+
+ + Joint-Task Regularization (JTR) leverages cross-task relations + to improve learning when data is not fully labeled for all tasks. + + + Poster + + +
+
Abstract
+
+ + Multi-task learning has become increasingly popular in the machine + learning field, but its practicality is hindered by the need for large, + labeled datasets. Most multi-task learning methods depend on fully labeled + datasets wherein each input example is accompanied by ground-truth labels + for all target tasks. Unfortunately, curating such datasets can be prohibitively + expensive and impractical, especially for dense prediction tasks which require + per-pixel labels for each image. With this in mind, we propose Joint-Task + Regularization (JTR), an intuitive technique which leverages cross-task + relations to simultaneously regularize all tasks in a single joint-task + latent space to improve learning when data is not fully labeled for all tasks. + JTR stands out from existing approaches in that it regularizes all tasks jointly + rather than separately in pairs -- therefore, it achieves linear complexity relative + to the number of tasks while previous methods scale quadratically. To demonstrate + the validity of our approach, we extensively benchmark our method across a wide + variety of partially labeled scenarios based on NYU-v2, Cityscapes, and Taskonomy. + + Overview +
+
BibTeX Citation
+
+ +
{bibtex}
+
+
+
+ + diff --git a/website/src/lib/index.ts b/website/src/lib/index.ts new file mode 100644 index 0000000..856f2b6 --- /dev/null +++ b/website/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/website/src/routes/+layout.svelte b/website/src/routes/+layout.svelte new file mode 100644 index 0000000..8dc2889 --- /dev/null +++ b/website/src/routes/+layout.svelte @@ -0,0 +1,7 @@ + + +
+ +
diff --git a/website/src/routes/+layout.ts b/website/src/routes/+layout.ts new file mode 100644 index 0000000..e69de29 diff --git a/website/src/routes/+page.svelte b/website/src/routes/+page.svelte new file mode 100644 index 0000000..59c3ddb --- /dev/null +++ b/website/src/routes/+page.svelte @@ -0,0 +1,34 @@ + + + + Joint-Task Regularization for Partially Labeled Multi-Task Learning + + +{#if !mounted} + +{/if} + +
+ +
+ + diff --git a/website/src/ts/constants.ts b/website/src/ts/constants.ts new file mode 100644 index 0000000..874028c --- /dev/null +++ b/website/src/ts/constants.ts @@ -0,0 +1 @@ +export const STAGGER = 0.05; diff --git a/website/static/favicon.png b/website/static/favicon.png new file mode 100644 index 0000000..8d9bd85 Binary files /dev/null and b/website/static/favicon.png differ diff --git a/website/svelte.config.js b/website/svelte.config.js new file mode 100644 index 0000000..fe4e7ca --- /dev/null +++ b/website/svelte.config.js @@ -0,0 +1,27 @@ +import adapter from '@sveltejs/adapter-static'; +import { vitePreprocess } from '@sveltejs/vite-plugin-svelte'; + +/** @type {import('@sveltejs/kit').Config} */ +const config = { + // Consult https://kit.svelte.dev/docs/integrations#preprocessors + // for more information about preprocessors + preprocess: vitePreprocess(), + + kit: { + // adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list. + // If your environment is not supported or you settled on a specific environment, switch out the adapter. + // See https://kit.svelte.dev/docs/adapters for more information about adapters. + adapter: adapter({ + pages: 'build', + assets: 'build', + precompress: false, + fallback: 'index.html', + strict: false, + }), + paths: { + base: '/JTR-CVPR-2024', + } + } +}; + +export default config; diff --git a/website/tsconfig.json b/website/tsconfig.json new file mode 100644 index 0000000..fc93cbd --- /dev/null +++ b/website/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "strict": true, + "moduleResolution": "bundler" + } + // Path aliases are handled by https://kit.svelte.dev/docs/configuration#alias + // except $lib which is handled by https://kit.svelte.dev/docs/configuration#files + // + // If you want to overwrite includes/excludes, make sure to copy over the relevant includes/excludes + // from the referenced tsconfig.json - TypeScript does not merge them in +} diff --git a/website/vite.config.ts b/website/vite.config.ts new file mode 100644 index 0000000..fce9e87 --- /dev/null +++ b/website/vite.config.ts @@ -0,0 +1,6 @@ +import { sveltekit } from '@sveltejs/kit/vite'; +import { defineConfig } from 'vite'; + +export default defineConfig({ + plugins: [sveltekit()], +}); diff --git a/website/yarn.lock b/website/yarn.lock new file mode 100644 index 0000000..c9a8066 --- /dev/null +++ b/website/yarn.lock @@ -0,0 +1,1753 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.1": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@esbuild/aix-ppc64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537" + integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g== + +"@esbuild/android-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9" + integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg== + +"@esbuild/android-arm@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995" + integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w== + +"@esbuild/android-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98" + integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg== + +"@esbuild/darwin-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb" + integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA== + +"@esbuild/darwin-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0" + integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA== + +"@esbuild/freebsd-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911" + integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw== + +"@esbuild/freebsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c" + integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw== + +"@esbuild/linux-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5" + integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A== + +"@esbuild/linux-arm@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c" + integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg== + +"@esbuild/linux-ia32@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa" + integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig== + +"@esbuild/linux-loong64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5" + integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ== + +"@esbuild/linux-mips64el@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa" + integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA== + +"@esbuild/linux-ppc64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20" + integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg== + +"@esbuild/linux-riscv64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300" + integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg== + +"@esbuild/linux-s390x@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685" + integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ== + +"@esbuild/linux-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff" + integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw== + +"@esbuild/netbsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6" + integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ== + +"@esbuild/openbsd-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf" + integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ== + +"@esbuild/sunos-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f" + integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w== + +"@esbuild/win32-arm64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90" + integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ== + +"@esbuild/win32-ia32@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23" + integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ== + +"@esbuild/win32-x64@0.20.2": + version "0.20.2" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc" + integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.10.0.tgz#548f6de556857c8bb73bbee70c35dc82a2e74d63" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.0": + version "8.57.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.0.tgz#a5417ae8427873f1dd08b70b3574b453e67b5f7f" + integrity sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g== + +"@humanwhocodes/config-array@^0.11.14": + version "0.11.14" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@polka/url@^1.0.0-next.24": + version "1.0.0-next.25" + resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.25.tgz#f077fdc0b5d0078d30893396ff4827a13f99e817" + integrity sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ== + +"@rollup/rollup-android-arm-eabi@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.14.0.tgz#57936f50d0335e2e7bfac496d209606fa516add4" + integrity sha512-jwXtxYbRt1V+CdQSy6Z+uZti7JF5irRKF8hlKfEnF/xJpcNGuuiZMBvuoYM+x9sr9iWGnzrlM0+9hvQ1kgkf1w== + +"@rollup/rollup-android-arm64@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.14.0.tgz#81bba83b37382a2d0e30ceced06c8d3d85138054" + integrity sha512-fI9nduZhCccjzlsA/OuAwtFGWocxA4gqXGTLvOyiF8d+8o0fZUeSztixkYjcGq1fGZY3Tkq4yRvHPFxU+jdZ9Q== + +"@rollup/rollup-darwin-arm64@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.14.0.tgz#a371bd723a5c4c4a33376da72abfc3938066842b" + integrity sha512-BcnSPRM76/cD2gQC+rQNGBN6GStBs2pl/FpweW8JYuz5J/IEa0Fr4AtrPv766DB/6b2MZ/AfSIOSGw3nEIP8SA== + +"@rollup/rollup-darwin-x64@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.14.0.tgz#8baf2fda277c9729125017c65651296282412886" + integrity sha512-LDyFB9GRolGN7XI6955aFeI3wCdCUszFWumWU0deHA8VpR3nWRrjG6GtGjBrQxQKFevnUTHKCfPR4IvrW3kCgQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.14.0.tgz#822830a8f7388d5b81d04c69415408d3bab1079b" + integrity sha512-ygrGVhQP47mRh0AAD0zl6QqCbNsf0eTo+vgwkY6LunBcg0f2Jv365GXlDUECIyoXp1kKwL5WW6rsO429DBY/bA== + +"@rollup/rollup-linux-arm64-gnu@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.14.0.tgz#e20fbe1bd4414c7119f9e0bba8ad17a6666c8365" + integrity sha512-x+uJ6MAYRlHGe9wi4HQjxpaKHPM3d3JjqqCkeC5gpnnI6OWovLdXTpfa8trjxPLnWKyBsSi5kne+146GAxFt4A== + +"@rollup/rollup-linux-arm64-musl@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.14.0.tgz#13f475596a62e1924f13fe1c8cf2c40e09a99b47" + integrity sha512-nrRw8ZTQKg6+Lttwqo6a2VxR9tOroa2m91XbdQ2sUUzHoedXlsyvY1fN4xWdqz8PKmf4orDwejxXHjh7YBGUCA== + +"@rollup/rollup-linux-powerpc64le-gnu@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.14.0.tgz#6a431c441420d1c510a205e08c6673355a0a2ea9" + integrity sha512-xV0d5jDb4aFu84XKr+lcUJ9y3qpIWhttO3Qev97z8DKLXR62LC3cXT/bMZXrjLF9X+P5oSmJTzAhqwUbY96PnA== + +"@rollup/rollup-linux-riscv64-gnu@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.14.0.tgz#53d9448962c3f9ed7a1672269655476ea2d67567" + integrity sha512-SDDhBQwZX6LPRoPYjAZWyL27LbcBo7WdBFWJi5PI9RPCzU8ijzkQn7tt8NXiXRiFMJCVpkuMkBf4OxSxVMizAw== + +"@rollup/rollup-linux-s390x-gnu@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.14.0.tgz#95f0c133b324da3e7e5c7d12855e0eb71d21a946" + integrity sha512-RxB/qez8zIDshNJDufYlTT0ZTVut5eCpAZ3bdXDU9yTxBzui3KhbGjROK2OYTTor7alM7XBhssgoO3CZ0XD3qA== + +"@rollup/rollup-linux-x64-gnu@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.14.0.tgz#820ada75c68ead1acc486e41238ca0d8f8531478" + integrity sha512-C6y6z2eCNCfhZxT9u+jAM2Fup89ZjiG5pIzZIDycs1IwESviLxwkQcFRGLjnDrP+PT+v5i4YFvlcfAs+LnreXg== + +"@rollup/rollup-linux-x64-musl@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.14.0.tgz#ca74f22e125efbe94c1148d989ef93329b464443" + integrity sha512-i0QwbHYfnOMYsBEyjxcwGu5SMIi9sImDVjDg087hpzXqhBSosxkE7gyIYFHgfFl4mr7RrXksIBZ4DoLoP4FhJg== + +"@rollup/rollup-win32-arm64-msvc@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.14.0.tgz#269023332297051d037a9593dcba92c10fef726b" + integrity sha512-Fq52EYb0riNHLBTAcL0cun+rRwyZ10S9vKzhGKKgeD+XbwunszSY0rVMco5KbOsTlwovP2rTOkiII/fQ4ih/zQ== + +"@rollup/rollup-win32-ia32-msvc@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.14.0.tgz#d7701438daf964011fd7ca33e3f13f3ff5129e7b" + integrity sha512-e/PBHxPdJ00O9p5Ui43+vixSgVf4NlLsmV6QneGERJ3lnjIua/kim6PRFe3iDueT1rQcgSkYP8ZBBXa/h4iPvw== + +"@rollup/rollup-win32-x64-msvc@4.14.0": + version "4.14.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.14.0.tgz#0bb7ac3cd1c3292db1f39afdabfd03ccea3a3d34" + integrity sha512-aGg7iToJjdklmxlUlJh/PaPNa4PmqHfyRMLunbL3eaMO0gp656+q1zOKkpJ/CVe9CryJv6tAN1HDoR8cNGzkag== + +"@sveltejs/adapter-auto@^3.0.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@sveltejs/adapter-auto/-/adapter-auto-3.2.0.tgz#00720dfad99f95452c6e47cc64a1cb58324337d2" + integrity sha512-She5nKT47kwHE18v9NMe6pbJcvULr82u0V3yZ0ej3n1laWKGgkgdEABE9/ak5iDPs93LqsBkuIo51kkwCLBjJA== + dependencies: + import-meta-resolve "^4.0.0" + +"@sveltejs/adapter-static@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sveltejs/adapter-static/-/adapter-static-3.0.1.tgz#64c36020435d7b1eacd362b2d027fefda5ec2e44" + integrity sha512-6lMvf7xYEJ+oGeR5L8DFJJrowkefTK6ZgA4JiMqoClMkKq0s6yvsd3FZfCFvX1fQ0tpCD7fkuRVHsnUVgsHyNg== + +"@sveltejs/kit@^2.0.0": + version "2.5.5" + resolved "https://registry.yarnpkg.com/@sveltejs/kit/-/kit-2.5.5.tgz#ceb4e2ec35bc82a5fedebc97a02c51815b8b0d32" + integrity sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ== + dependencies: + "@types/cookie" "^0.6.0" + cookie "^0.6.0" + devalue "^4.3.2" + esm-env "^1.0.0" + import-meta-resolve "^4.0.0" + kleur "^4.1.5" + magic-string "^0.30.5" + mrmime "^2.0.0" + sade "^1.8.1" + set-cookie-parser "^2.6.0" + sirv "^2.0.4" + tiny-glob "^0.2.9" + +"@sveltejs/vite-plugin-svelte-inspector@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-2.0.0.tgz#365afaa0dd63517838ce4686a3dc3982be348a9b" + integrity sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg== + dependencies: + debug "^4.3.4" + +"@sveltejs/vite-plugin-svelte@^3.0.0": + version "3.0.2" + resolved "https://registry.yarnpkg.com/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-3.0.2.tgz#5c33534d07130283cff92304f627010387c11af0" + integrity sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q== + dependencies: + "@sveltejs/vite-plugin-svelte-inspector" "^2.0.0" + debug "^4.3.4" + deepmerge "^4.3.1" + kleur "^4.1.5" + magic-string "^0.30.5" + svelte-hmr "^0.15.3" + vitefu "^0.2.5" + +"@types/cookie@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5" + integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA== + +"@types/eslint@^8.56.0": + version "8.56.7" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.56.7.tgz#c33b5b5a9cfb66881beb7b5be6c34aa3e81d3366" + integrity sha512-SjDvI/x3zsZnOkYZ3lCt9lOZWZLB2jIlNKz+LBgCtDurK0JZcwucxYHn1w2BJkD34dgX9Tjnak0txtq4WTggEA== + dependencies: + "@types/estree" "*" + "@types/json-schema" "*" + +"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.1": + version "1.0.5" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" + integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== + +"@types/json-schema@*", "@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/pug@^2.0.6": + version "2.0.10" + resolved "https://registry.yarnpkg.com/@types/pug/-/pug-2.0.10.tgz#52f8dbd6113517aef901db20b4f3fca543b88c1f" + integrity sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA== + +"@types/semver@^7.5.0": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + +"@typescript-eslint/eslint-plugin@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.5.0.tgz#1dc52fe48454d5b54be2d5f089680452f1628a5a" + integrity sha512-HpqNTH8Du34nLxbKgVMGljZMG0rJd2O9ecvr2QLYp+7512ty1j42KnsFwspPXg1Vh8an9YImf6CokUBltisZFQ== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "7.5.0" + "@typescript-eslint/type-utils" "7.5.0" + "@typescript-eslint/utils" "7.5.0" + "@typescript-eslint/visitor-keys" "7.5.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^7.0.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-7.5.0.tgz#1eeff36309ac2253c905dd4a88b4b71b72a358ed" + integrity sha512-cj+XGhNujfD2/wzR1tabNsidnYRaFfEkcULdcIyVBYcXjBvBKOes+mpMBP7hMpOyk+gBcfXsrg4NBGAStQyxjQ== + dependencies: + "@typescript-eslint/scope-manager" "7.5.0" + "@typescript-eslint/types" "7.5.0" + "@typescript-eslint/typescript-estree" "7.5.0" + "@typescript-eslint/visitor-keys" "7.5.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.5.0.tgz#70f0a7361430ab1043a5f97386da2a0d8b2f4d56" + integrity sha512-Z1r7uJY0MDeUlql9XJ6kRVgk/sP11sr3HKXn268HZyqL7i4cEfrdFuSSY/0tUqT37l5zT0tJOsuDP16kio85iA== + dependencies: + "@typescript-eslint/types" "7.5.0" + "@typescript-eslint/visitor-keys" "7.5.0" + +"@typescript-eslint/type-utils@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.5.0.tgz#a8faa403232da3a3901655387c7082111f692cf9" + integrity sha512-A021Rj33+G8mx2Dqh0nMO9GyjjIBK3MqgVgZ2qlKf6CJy51wY/lkkFqq3TqqnH34XyAHUkq27IjlUkWlQRpLHw== + dependencies: + "@typescript-eslint/typescript-estree" "7.5.0" + "@typescript-eslint/utils" "7.5.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.5.0.tgz#0a284bcdef3cb850ec9fd57992df9f29d6bde1bc" + integrity sha512-tv5B4IHeAdhR7uS4+bf8Ov3k793VEVHd45viRRkehIUZxm0WF82VPiLgHzA/Xl4TGPg1ZD49vfxBKFPecD5/mg== + +"@typescript-eslint/typescript-estree@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.5.0.tgz#aa5031c511874420f6b5edd90f8e4021525ee776" + integrity sha512-YklQQfe0Rv2PZEueLTUffiQGKQneiIEKKnfIqPIOxgM9lKSZFCjT5Ad4VqRKj/U4+kQE3fa8YQpskViL7WjdPQ== + dependencies: + "@typescript-eslint/types" "7.5.0" + "@typescript-eslint/visitor-keys" "7.5.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.5.0.tgz#bbd963647fbbe9ffea033f42c0fb7e89bb19c858" + integrity sha512-3vZl9u0R+/FLQcpy2EHyRGNqAS/ofJ3Ji8aebilfJe+fobK8+LbIFmrHciLVDxjDoONmufDcnVSF38KwMEOjzw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "7.5.0" + "@typescript-eslint/types" "7.5.0" + "@typescript-eslint/typescript-estree" "7.5.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@7.5.0": + version "7.5.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.5.0.tgz#8abcac66f93ef20b093e87a400c2d21e3a6d55ee" + integrity sha512-mcuHM/QircmA6O7fy6nn2w/3ditQkj+SgtOc8DW3uQ10Yfj42amm2i+6F2K4YAOPNNTmE6iM1ynM6lrSwdendA== + dependencies: + "@typescript-eslint/types" "7.5.0" + eslint-visitor-keys "^3.4.1" + +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.0.tgz#756641adb587851b5ccb3e095daf27ae581c8406" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.10.0, acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +aria-query@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-5.3.0.tgz#650c569e41ad90b51b3d7df5e5eed1c7549c103e" + integrity sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A== + dependencies: + dequal "^2.0.3" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +axobject-query@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-4.0.0.tgz#04a4c90dce33cc5d606c76d6216e3b250ff70dab" + integrity sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw== + dependencies: + dequal "^2.0.3" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +buffer-crc32@^0.2.5: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.4.1: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +code-red@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/code-red/-/code-red-1.0.4.tgz#59ba5c9d1d320a4ef795bc10a28bd42bfebe3e35" + integrity sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + "@types/estree" "^1.0.1" + acorn "^8.10.0" + estree-walker "^3.0.3" + periscopic "^3.1.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cookie@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" + integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== + +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +css-tree@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-2.3.1.tgz#10264ce1e5442e8572fc82fbe490644ff54b5c20" + integrity sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw== + dependencies: + mdn-data "2.0.30" + source-map-js "^1.0.1" + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +dequal@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" + integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== + +detect-indent@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" + integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== + +devalue@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/devalue/-/devalue-4.3.2.tgz#cc44e4cf3872ac5a78229fbce3b77e57032727b5" + integrity sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg== + +dialog-polyfill@^0.5.6: + version "0.5.6" + resolved "https://registry.yarnpkg.com/dialog-polyfill/-/dialog-polyfill-0.5.6.tgz#7507b4c745a82fcee0fa07ce64d835979719599a" + integrity sha512-ZbVDJI9uvxPAKze6z146rmfUZjBqNEwcnFTVamQzXH+svluiV7swmVIGr7miwADgfgt1G2JQIytypM9fbyhX4w== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + +es6-promise@^3.1.2: + version "3.3.1" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-3.3.1.tgz#a08cdde84ccdbf34d027a1451bc91d4bcd28a613" + integrity sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg== + +esbuild@^0.20.1: + version "0.20.2" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.2.tgz#9d6b2386561766ee6b5a55196c6d766d28c87ea1" + integrity sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g== + optionalDependencies: + "@esbuild/aix-ppc64" "0.20.2" + "@esbuild/android-arm" "0.20.2" + "@esbuild/android-arm64" "0.20.2" + "@esbuild/android-x64" "0.20.2" + "@esbuild/darwin-arm64" "0.20.2" + "@esbuild/darwin-x64" "0.20.2" + "@esbuild/freebsd-arm64" "0.20.2" + "@esbuild/freebsd-x64" "0.20.2" + "@esbuild/linux-arm" "0.20.2" + "@esbuild/linux-arm64" "0.20.2" + "@esbuild/linux-ia32" "0.20.2" + "@esbuild/linux-loong64" "0.20.2" + "@esbuild/linux-mips64el" "0.20.2" + "@esbuild/linux-ppc64" "0.20.2" + "@esbuild/linux-riscv64" "0.20.2" + "@esbuild/linux-s390x" "0.20.2" + "@esbuild/linux-x64" "0.20.2" + "@esbuild/netbsd-x64" "0.20.2" + "@esbuild/openbsd-x64" "0.20.2" + "@esbuild/sunos-x64" "0.20.2" + "@esbuild/win32-arm64" "0.20.2" + "@esbuild/win32-ia32" "0.20.2" + "@esbuild/win32-x64" "0.20.2" + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-compat-utils@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz#f45e3b5ced4c746c127cf724fb074cd4e730d653" + integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== + +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-plugin-svelte@^2.35.1: + version "2.35.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-svelte/-/eslint-plugin-svelte-2.35.1.tgz#7b1e3c263b09dbc9293c25fe02d03d309725d2b9" + integrity sha512-IF8TpLnROSGy98Z3NrsKXWDSCbNY2ReHDcrYTuXZMbfX7VmESISR78TWgO9zdg4Dht1X8coub5jKwHzP0ExRug== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + debug "^4.3.1" + eslint-compat-utils "^0.1.2" + esutils "^2.0.3" + known-css-properties "^0.29.0" + postcss "^8.4.5" + postcss-load-config "^3.1.4" + postcss-safe-parser "^6.0.0" + postcss-selector-parser "^6.0.11" + semver "^7.5.3" + svelte-eslint-parser ">=0.33.0 <1.0.0" + +eslint-scope@^7.0.0, eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.0.0, eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@^8.56.0: + version "8.57.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" + integrity sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.0" + "@humanwhocodes/config-array" "^0.11.14" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +esm-env@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esm-env/-/esm-env-1.0.0.tgz#b124b40b180711690a4cb9b00d16573391950413" + integrity sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA== + +espree@^9.0.0, espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +estree-walker@^3.0.0, estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +esutils@^2.0.2, esutils@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +exio@^0.6.45: + version "0.6.45" + resolved "https://registry.yarnpkg.com/exio/-/exio-0.6.45.tgz#0d5e70f665f613afbf7a85fcedb70be446c9be06" + integrity sha512-ewv6r6zpLqAia8QPBhMr72ga8/qb+KOawhzFH4okoMEpbL1KTOVWlqCUgeiWvCLVEQ7eCAnFor+Zus4a6INF5w== + dependencies: + dialog-polyfill "^0.5.6" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.7, fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +glob-parent@^5.1.2, glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalyzer@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/globalyzer/-/globalyzer-0.1.0.tgz#cb76da79555669a1519d5a8edf093afaa0bf1465" + integrity sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q== + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +globrex@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/globrex/-/globrex-0.1.2.tgz#dd5d9ec826232730cd6793a5e33a9302985e6098" + integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== + +graceful-fs@^4.1.3: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.1" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-meta-resolve@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz#0b1195915689f60ab00f830af0f15cc841e8919e" + integrity sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA== + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-reference@^3.0.0, is-reference@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-3.0.2.tgz#154747a01f45cd962404ee89d43837af2cba247c" + integrity sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg== + dependencies: + "@types/estree" "*" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" + integrity sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ== + +known-css-properties@^0.29.0: + version "0.29.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.29.0.tgz#e8ba024fb03886f23cb882e806929f32d814158f" + integrity sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lilconfig@^2.0.5: + version "2.1.0" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" + integrity sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ== + +locate-character@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/locate-character/-/locate-character-3.0.0.tgz#0305c5b8744f61028ef5d01f444009e00779f974" + integrity sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +magic-string@^0.30.4, magic-string@^0.30.5: + version "0.30.9" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.9.tgz#8927ae21bfdd856310e07a1bc8dd5e73cb6c251d" + integrity sha512-S1+hd+dIrC8EZqKyT9DstTH/0Z+f76kmmvZnkfQVmOpDEF9iVgdYif3Q/pIWHmCoo59bQVGW0kVL3e2nl+9+Sw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.15" + +mdn-data@2.0.30: + version "2.0.30" + resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.30.tgz#ce4df6f80af6cfbe218ecd5c552ba13c4dfa08cc" + integrity sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA== + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + +mrmime@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" + integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +nanoid@^3.3.7: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +periscopic@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/periscopic/-/periscopic-3.1.0.tgz#7e9037bf51c5855bd33b48928828db4afa79d97a" + integrity sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw== + dependencies: + "@types/estree" "^1.0.0" + estree-walker "^3.0.0" + is-reference "^3.0.0" + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +postcss-load-config@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-3.1.4.tgz#1ab2571faf84bb078877e1d07905eabe9ebda855" + integrity sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg== + dependencies: + lilconfig "^2.0.5" + yaml "^1.10.2" + +postcss-safe-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" + integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== + +postcss-scss@^4.0.8: + version "4.0.9" + resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-4.0.9.tgz#a03c773cd4c9623cb04ce142a52afcec74806685" + integrity sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A== + +postcss-selector-parser@^6.0.11: + version "6.0.16" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz#3b88b9f5c5abd989ef4e2fc9ec8eedd34b20fb04" + integrity sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss@^8.4.29, postcss@^8.4.38, postcss@^8.4.5: + version "8.4.38" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" + integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== + dependencies: + nanoid "^3.3.7" + picocolors "^1.0.0" + source-map-js "^1.2.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-plugin-svelte@^3.1.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.2.tgz#df576c8a92088dc0aaec8e27fce8a7d9683de93c" + integrity sha512-ZzzE/wMuf48/1+Lf2Ffko0uDa6pyCfgHV6+uAhtg2U0AAXGrhCSW88vEJNAkAxW5qyrFY1y1zZ4J8TgHrjW++Q== + +prettier@^3.1.1: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^2.5.2: + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + +rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rollup@^4.13.0: + version "4.14.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.14.0.tgz#c3e2cd479f1b2358b65c1f810fa05b51603d7be8" + integrity sha512-Qe7w62TyawbDzB4yt32R0+AbIo6m1/sqO7UPzFS8Z/ksL5mrfhA0v4CavfdmFav3D+ub4QeAgsGEe84DoWe/nQ== + dependencies: + "@types/estree" "1.0.5" + optionalDependencies: + "@rollup/rollup-android-arm-eabi" "4.14.0" + "@rollup/rollup-android-arm64" "4.14.0" + "@rollup/rollup-darwin-arm64" "4.14.0" + "@rollup/rollup-darwin-x64" "4.14.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.14.0" + "@rollup/rollup-linux-arm64-gnu" "4.14.0" + "@rollup/rollup-linux-arm64-musl" "4.14.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.14.0" + "@rollup/rollup-linux-riscv64-gnu" "4.14.0" + "@rollup/rollup-linux-s390x-gnu" "4.14.0" + "@rollup/rollup-linux-x64-gnu" "4.14.0" + "@rollup/rollup-linux-x64-musl" "4.14.0" + "@rollup/rollup-win32-arm64-msvc" "4.14.0" + "@rollup/rollup-win32-ia32-msvc" "4.14.0" + "@rollup/rollup-win32-x64-msvc" "4.14.0" + fsevents "~2.3.2" + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +sade@^1.7.4, sade@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + +sander@^0.5.0: + version "0.5.1" + resolved "https://registry.yarnpkg.com/sander/-/sander-0.5.1.tgz#741e245e231f07cafb6fdf0f133adfa216a502ad" + integrity sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA== + dependencies: + es6-promise "^3.1.2" + graceful-fs "^4.1.3" + mkdirp "^0.5.1" + rimraf "^2.5.2" + +semver@^7.5.3, semver@^7.5.4: + version "7.6.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + +set-cookie-parser@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz#131921e50f62ff1a66a461d7d62d7b21d5d15a51" + integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +sirv@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/sirv/-/sirv-2.0.4.tgz#5dd9a725c578e34e449f332703eb2a74e46a29b0" + integrity sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ== + dependencies: + "@polka/url" "^1.0.0-next.24" + mrmime "^2.0.0" + totalist "^3.0.0" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +sorcery@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/sorcery/-/sorcery-0.11.0.tgz#310c80ee993433854bb55bb9aa4003acd147fca8" + integrity sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw== + dependencies: + "@jridgewell/sourcemap-codec" "^1.4.14" + buffer-crc32 "^0.2.5" + minimist "^1.2.0" + sander "^0.5.0" + +source-map-js@^1.0.1, source-map-js@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" + integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== + +strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +svelte-check@^3.6.0: + version "3.6.9" + resolved "https://registry.yarnpkg.com/svelte-check/-/svelte-check-3.6.9.tgz#05132d9a996aa8e12202a14644c03e3163267642" + integrity sha512-hDQrk3L0osX07djQyMiXocKysTLfusqi8AriNcCiQxhQR49/LonYolcUGMtZ0fbUR8HTR198Prrgf52WWU9wEg== + dependencies: + "@jridgewell/trace-mapping" "^0.3.17" + chokidar "^3.4.1" + fast-glob "^3.2.7" + import-fresh "^3.2.1" + picocolors "^1.0.0" + sade "^1.7.4" + svelte-preprocess "^5.1.3" + typescript "^5.0.3" + +"svelte-eslint-parser@>=0.33.0 <1.0.0": + version "0.33.1" + resolved "https://registry.yarnpkg.com/svelte-eslint-parser/-/svelte-eslint-parser-0.33.1.tgz#c64dbed2fad099577429b3c39377f6b8d36e5d97" + integrity sha512-vo7xPGTlKBGdLH8T5L64FipvTrqv3OQRx9d2z5X05KKZDlF4rQk8KViZO4flKERY+5BiVdOh7zZ7JGJWo5P0uA== + dependencies: + eslint-scope "^7.0.0" + eslint-visitor-keys "^3.0.0" + espree "^9.0.0" + postcss "^8.4.29" + postcss-scss "^4.0.8" + +svelte-hmr@^0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/svelte-hmr/-/svelte-hmr-0.15.3.tgz#df54ccde9be3f091bf5f18fc4ef7b8eb6405fbe6" + integrity sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ== + +svelte-preprocess@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/svelte-preprocess/-/svelte-preprocess-5.1.3.tgz#7682239fe53f724c845b53026816fdfe15d028f9" + integrity sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw== + dependencies: + "@types/pug" "^2.0.6" + detect-indent "^6.1.0" + magic-string "^0.30.5" + sorcery "^0.11.0" + strip-indent "^3.0.0" + +svelte@^4.2.7: + version "4.2.12" + resolved "https://registry.yarnpkg.com/svelte/-/svelte-4.2.12.tgz#13d98d2274d24d3ad216c8fdc801511171c70bb1" + integrity sha512-d8+wsh5TfPwqVzbm4/HCXC783/KPHV60NvwitJnyTA5lWn1elhXMNWhXGCJ7PwPa8qFUnyJNIyuIRt2mT0WMug== + dependencies: + "@ampproject/remapping" "^2.2.1" + "@jridgewell/sourcemap-codec" "^1.4.15" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/estree" "^1.0.1" + acorn "^8.9.0" + aria-query "^5.3.0" + axobject-query "^4.0.0" + code-red "^1.0.3" + css-tree "^2.3.1" + estree-walker "^3.0.3" + is-reference "^3.0.1" + locate-character "^3.0.0" + magic-string "^0.30.4" + periscopic "^3.1.0" + +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + +tiny-glob@^0.2.9: + version "0.2.9" + resolved "https://registry.yarnpkg.com/tiny-glob/-/tiny-glob-0.2.9.tgz#2212d441ac17928033b110f8b3640683129d31e2" + integrity sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg== + dependencies: + globalyzer "0.1.0" + globrex "^0.1.2" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +totalist@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" + integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== + +ts-api-utils@^1.0.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +tslib@^2.4.1: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +typescript@^5.0.0, typescript@^5.0.3: + version "5.4.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.3.tgz#5c6fedd4c87bee01cd7a528a30145521f8e0feff" + integrity sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +vite@^5.0.3: + version "5.2.8" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.8.tgz#a99e09939f1a502992381395ce93efa40a2844aa" + integrity sha512-OyZR+c1CE8yeHw5V5t59aXsUPPVTHMDjEZz8MgguLL/Q7NblxhZUlTu9xSPqlsUO/y+X7dlU05jdhvyycD55DA== + dependencies: + esbuild "^0.20.1" + postcss "^8.4.38" + rollup "^4.13.0" + optionalDependencies: + fsevents "~2.3.3" + +vitefu@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/vitefu/-/vitefu-0.2.5.tgz#c1b93c377fbdd3e5ddd69840ea3aa70b40d90969" + integrity sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q== + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yaml@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==